├── .gitignore ├── LICENSE ├── libuv-sys ├── Cargo.toml ├── build.rs └── src │ └── lib.rs ├── libuv ├── Cargo.toml └── src │ └── lib.rs └── thread-bound ├── Cargo.toml └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | libuv-sys/libuv 4 | libuv-sys/libuv.stamp 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Stefan O'Rear 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /libuv-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libuv-sys" 3 | version = "0.1.0" 4 | authors = ["Stefan O'Rear "] 5 | build = "build.rs" 6 | repository = "https://github.com/sorear/libuv-rs" 7 | description = "Native bindings to the libuv library" 8 | license = "MIT" 9 | # todo: readme, documentation, homepage, keywords? 10 | exclude = ["libuv/*"] 11 | 12 | [build-dependencies] 13 | pkg-config = "0.3.6" 14 | 15 | [dependencies] 16 | libc = "0.1.10" 17 | 18 | # [lib] 19 | # crate-type = ["dylib"] 20 | -------------------------------------------------------------------------------- /libuv-sys/build.rs: -------------------------------------------------------------------------------- 1 | // Port of https://github.com/saghul/pyuv/blob/v1.x/setup_libuv.py 2 | extern crate pkg_config; 3 | 4 | use std::fs; 5 | use std::path::{Path, PathBuf}; 6 | use std::env; 7 | use std::process::Command; 8 | 9 | fn libuv_dir() -> PathBuf { 10 | Path::new("libuv").to_owned() 11 | } 12 | fn libuv_repo() -> String { 13 | "https://github.com/libuv/libuv.git".to_owned() 14 | } 15 | fn libuv_revision() -> String { 16 | "v1.9.1".to_owned() 17 | } 18 | fn libuv_lib() -> PathBuf { 19 | if cfg!(windows) { 20 | libuv_dir().join("Release").join("lib").join("libuv.lib") 21 | } else { 22 | libuv_dir().join(".libs").join("libuv.a") 23 | } 24 | } 25 | 26 | fn libuv_force_fetch() -> bool { 27 | env::var("LIBUV_SYS_FORCE_FETCH").is_ok() 28 | } 29 | fn libuv_clean_compile() -> bool { 30 | env::var("LIBUV_SYS_CLEAN_COMPILE").is_ok() 31 | } 32 | fn use_system_libuv() -> bool { 33 | env::var("LIBUV_SYS_USE_SYSTEM").is_ok() 34 | } 35 | 36 | fn download_libuv() { 37 | println!("Downloading libuv..."); 38 | fs::create_dir_all(libuv_dir()).unwrap(); 39 | Command::new("git") 40 | .arg("clone") 41 | .arg("-b") 42 | .arg(libuv_revision()) 43 | .arg(libuv_repo()) 44 | .arg(libuv_dir()) 45 | .spawn() 46 | .unwrap() 47 | .wait() 48 | .unwrap(); 49 | fs::create_dir_all("libuv.stamp").unwrap(); 50 | } 51 | 52 | fn build_libuv() { 53 | println!("Building libuv..."); 54 | // don't support cross-compiling ... 55 | if cfg!(windows) { 56 | let libuv_arch = if cfg!(target_arch = "x86") { 57 | "x86" 58 | } else if cfg!(target_arch = "x86_64") { 59 | "x64" 60 | } else { 61 | panic!("Unsupported Windows host architecture") 62 | }; 63 | // deleted some environment stuff ("setup_windows_env") that looked fairly 64 | // Python-specific 65 | Command::new("cmd.exe") 66 | .arg("/C") 67 | .arg("vcbuild.bat") 68 | .arg(libuv_arch) 69 | .arg("release") 70 | .current_dir(libuv_dir()) 71 | .spawn() 72 | .unwrap() 73 | .wait() 74 | .unwrap(); 75 | } else { 76 | Command::new("sh") 77 | .arg("autogen.sh") 78 | .current_dir(libuv_dir()) 79 | .spawn() 80 | .unwrap() 81 | .wait() 82 | .unwrap(); 83 | Command::new("./configure") 84 | .current_dir(libuv_dir()) 85 | .spawn() 86 | .unwrap() 87 | .wait() 88 | .unwrap(); 89 | Command::new("make") 90 | .current_dir(libuv_dir()) 91 | .spawn() 92 | .unwrap() 93 | .wait() 94 | .unwrap(); 95 | } 96 | } 97 | 98 | fn get_libuv() { 99 | if libuv_force_fetch() { 100 | fs::remove_dir_all(libuv_dir()).unwrap(); 101 | fs::remove_dir_all("libuv.stamp").unwrap(); 102 | } 103 | 104 | if fs::metadata("libuv.stamp").is_err() { 105 | download_libuv(); 106 | build_libuv(); 107 | } else { 108 | if libuv_clean_compile() { 109 | if cfg!(windows) { 110 | Command::new("cmd.exe") 111 | .arg("/C") 112 | .arg("vcbuild.bat") 113 | .arg("clean") 114 | .current_dir(libuv_dir()) 115 | .spawn() 116 | .unwrap() 117 | .wait() 118 | .unwrap(); 119 | fs::remove_dir_all(libuv_dir().join("Release")).unwrap(); 120 | } else { 121 | Command::new("make") 122 | .arg("clean") 123 | .current_dir(libuv_dir()) 124 | .spawn() 125 | .unwrap() 126 | .wait() 127 | .unwrap(); 128 | Command::new("make") 129 | .arg("distclean") 130 | .current_dir(libuv_dir()) 131 | .spawn() 132 | .unwrap() 133 | .wait() 134 | .unwrap(); 135 | } 136 | } 137 | 138 | if fs::metadata(libuv_lib()).is_err() { 139 | println!("libuv needs to be compiled."); 140 | build_libuv(); 141 | } else { 142 | println!("No need to build libuv."); 143 | } 144 | } 145 | } 146 | 147 | fn main() { 148 | let target = env::var("TARGET").unwrap(); 149 | if cfg!(windows) != target.contains("windows") { 150 | panic!("Cannot cross compile to/from Windows due to use of a batch file build"); 151 | } 152 | 153 | if use_system_libuv() { 154 | pkg_config::find_library("libuv").unwrap(); 155 | } else { 156 | get_libuv(); 157 | println!("cargo:rustc-link-lib=static=uv"); 158 | println!("cargo:rustc-link-search=native={}", 159 | env::current_dir().unwrap().join(libuv_lib().parent().unwrap()).to_str().unwrap()); 160 | if target.contains("linux") { 161 | println!("cargo:rustc-link-lib=rt"); 162 | } else if target.contains("windows") { 163 | println!("cargo:rustc-link-lib=advapi32"); 164 | println!("cargo:rustc-link-lib=iphlpapi"); 165 | println!("cargo:rustc-link-lib=psapi"); 166 | println!("cargo:rustc-link-lib=shell32"); 167 | println!("cargo:rustc-link-lib=userenv"); 168 | println!("cargo:rustc-link-lib=ws2_32"); 169 | } else if target.contains("freebsd") { 170 | println!("cargo:rustc-link-lib=kvm"); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /libuv-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | extern crate libc; 3 | use libc::{c_int, c_char, c_uint, c_void, uint64_t, size_t, sockaddr, sockaddr_in6, int64_t, 4 | ssize_t, addrinfo, c_long, sockaddr_in, sockaddr_storage}; 5 | #[cfg(windows)] 6 | extern crate winapi; 7 | #[cfg(windows)] 8 | use winapi::{OVERLAPPED, HANDLE}; 9 | 10 | #[cfg(windows)] 11 | mod variable_types { 12 | use libc::c_uchar; 13 | use winapi::{ULONG, SOCKET, HANDLE}; 14 | // undocumented 15 | pub type uv_uid_t = c_uchar; 16 | pub type uv_gid_t = c_uchar; 17 | 18 | // misc.rst 19 | #[repr(C)] 20 | #[derive(Debug,Clone,Copy)] 21 | pub struct uv_buf_t { 22 | pub len: ULONG, 23 | pub base: *mut c_char, 24 | } 25 | 26 | pub type uv_os_sock_t = SOCKET; 27 | pub type uv_os_fd_t = HANDLE; 28 | } 29 | 30 | #[cfg(not(windows))] 31 | mod variable_types { 32 | use libc::{c_int, uid_t, gid_t, c_char, size_t}; 33 | // undocumented 34 | pub type uv_uid_t = uid_t; 35 | pub type uv_gid_t = gid_t; 36 | 37 | // misc.rst 38 | #[repr(C)] 39 | #[derive(Debug,Clone,Copy)] 40 | pub struct uv_buf_t { 41 | pub base: *mut c_char, 42 | pub len: size_t, 43 | } 44 | 45 | pub type uv_os_sock_t = c_int; 46 | pub type uv_os_fd_t = c_int; 47 | } 48 | 49 | pub use variable_types::*; 50 | 51 | // undocumented 52 | 53 | #[repr(C)] 54 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 55 | pub struct uv_timeval_t { 56 | pub tv_sec: c_long, 57 | pub tv_usec: c_long, 58 | } 59 | 60 | #[repr(C)] 61 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 62 | pub enum uv_handle_type { 63 | UV_UNKNOWN_HANDLE = 0, 64 | UV_ASYNC = 1, 65 | UV_CHECK = 2, 66 | UV_FS_EVENT = 3, 67 | UV_FS_POLL = 4, 68 | UV_HANDLE = 5, 69 | UV_IDLE = 6, 70 | UV_NAMED_PIPE = 7, 71 | UV_POLL = 8, 72 | UV_PREPARE = 9, 73 | UV_PROCESS = 10, 74 | UV_STREAM = 11, 75 | UV_TCP = 12, 76 | UV_TIMER = 13, 77 | UV_TTY = 14, 78 | UV_UDP = 15, 79 | UV_SIGNAL = 16, 80 | UV_FILE = 17, 81 | UV_HANDLE_TYPE_MAX = 18, 82 | } 83 | pub use uv_handle_type::*; 84 | 85 | // errors.rst 86 | 87 | // Not binding the individual UV_E* constants for now because they're a huge 88 | // mess. Use uv_err_name. 89 | 90 | extern { 91 | pub fn uv_strerror(err: c_int) -> *const c_char; 92 | pub fn uv_err_name(err: c_int) -> *const c_char; 93 | } 94 | 95 | // version.rst 96 | 97 | // Punting version macros for now ... use uv_version instead 98 | extern { 99 | pub fn uv_version() -> c_uint; 100 | pub fn uv_version_string() -> *const c_char; 101 | } 102 | 103 | // loop.rst 104 | 105 | #[repr(C)] 106 | pub struct uv_loop_t { 107 | pub data: *mut c_void, 108 | _private_fields: [u8; 0], 109 | } 110 | 111 | #[repr(C)] 112 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 113 | pub enum uv_run_mode { 114 | UV_RUN_DEFAULT = 0, 115 | UV_RUN_ONCE = 1, 116 | UV_RUN_NOWAIT = 2, 117 | } 118 | pub use uv_run_mode::*; 119 | 120 | #[repr(C)] 121 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 122 | pub enum uv_loop_option { 123 | UV_LOOP_BLOCK_SIGNAL = 0, 124 | dummy = 99, // https://github.com/rust-lang/rust/issues/10292 125 | } 126 | pub use uv_loop_option::UV_LOOP_BLOCK_SIGNAL; 127 | 128 | pub type uv_walk_cb = extern "C" fn (*mut uv_handle_t, *mut c_void); 129 | 130 | extern { 131 | pub fn uv_loop_init(loop_: *mut uv_loop_t) -> c_int; 132 | pub fn uv_loop_configure(loop_: *mut uv_loop_t, option: uv_loop_option, ...) -> c_int; 133 | pub fn uv_loop_close(loop_: *mut uv_loop_t) -> c_int; 134 | pub fn uv_default_loop() -> *mut uv_loop_t; 135 | pub fn uv_run(loop_: *mut uv_loop_t, mode: uv_run_mode) -> c_int; 136 | pub fn uv_loop_alive(loop_: *mut uv_loop_t) -> c_int; 137 | pub fn uv_stop(loop_: *mut uv_loop_t); 138 | pub fn uv_loop_size() -> size_t; 139 | pub fn uv_backend_fd(loop_: *const uv_loop_t) -> c_int; 140 | pub fn uv_backend_timeout(loop_: *const uv_loop_t) -> c_int; 141 | pub fn uv_now(loop_: *const uv_loop_t) -> uint64_t; 142 | pub fn uv_update_time(loop_: *mut uv_loop_t); 143 | pub fn uv_walk(loop_: *mut uv_loop_t, walk_cb: uv_walk_cb, arg: *mut c_void); 144 | } 145 | 146 | // handle.rst 147 | 148 | // the purpose of this is not to access the internal fields, but to reproduce 149 | // the size and alignment so that public fields in derived structs are visible 150 | macro_rules! handle_struct { 151 | ( $name:ident ) => { 152 | #[repr(C)] 153 | pub struct $name { 154 | pub data: *mut c_void, 155 | pub loop_: *mut uv_loop_t, // readonly 156 | pub type_: uv_handle_type, // readonly 157 | _h_private: [*mut c_void; 8], 158 | _flags: c_uint, 159 | } 160 | } 161 | } 162 | 163 | handle_struct!(uv_handle_t); 164 | 165 | pub type uv_alloc_cb = extern "C" fn(*mut uv_handle_t, size_t, *mut uv_buf_t); 166 | pub type uv_close_cb = extern "C" fn(*mut uv_handle_t); 167 | 168 | extern { 169 | pub fn uv_is_active(handle: *const uv_handle_t) -> c_int; 170 | pub fn uv_is_closing(handle: *const uv_handle_t) -> c_int; 171 | pub fn uv_close(handle: *mut uv_handle_t, close_cb: uv_close_cb); 172 | pub fn uv_ref(handle: *mut uv_handle_t); 173 | pub fn uv_unref(handle: *mut uv_handle_t); 174 | pub fn uv_has_ref(handle: *const uv_handle_t) -> c_int; 175 | pub fn uv_handle_size(type_: uv_handle_type) -> size_t; 176 | pub fn uv_send_buffer_size(handle: *mut uv_handle_t, value: *mut c_int) -> c_int; 177 | pub fn uv_recv_buffer_size(handle: *mut uv_handle_t, value: *mut c_int) -> c_int; 178 | pub fn uv_fileno(handle: *const uv_handle_t, fd: *mut uv_os_fd_t) -> c_int; 179 | } 180 | 181 | // request.rst 182 | 183 | // we can get away with this because it begins and ends with a pointer 184 | #[repr(C)] 185 | struct _request_private { 186 | _active_queue: [*mut c_void; 2], 187 | _reserved: [*mut c_void; 4], 188 | #[cfg(windows)] 189 | _u_io_overlapped: OVERLAPPED, 190 | } 191 | 192 | macro_rules! request_struct { 193 | ($name:ident) => { 194 | #[repr(C)] 195 | pub struct $name { 196 | pub data: *mut c_void, 197 | pub type_: uv_req_type, // readonly 198 | _r_private: _request_private, 199 | } 200 | } 201 | } 202 | 203 | request_struct!(uv_req_t); 204 | 205 | #[repr(C)] 206 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 207 | pub enum uv_req_type { 208 | UV_UNKNOWN_REQ = 0, 209 | UV_REQ = 1, 210 | UV_CONNECT = 2, 211 | UV_WRITE = 3, 212 | UV_SHUTDOWN = 4, 213 | UV_UDP_SEND = 5, 214 | UV_FS = 6, 215 | UV_WORK = 7, 216 | UV_GETADDRINFO = 8, 217 | UV_GETNAMEINFO = 9, // plus zero or more private types 218 | UV_REQ_TYPE_PRIVATE = 10, 219 | UV_REQ_TYPE_MAX = 11, 220 | } 221 | pub use uv_req_type::*; 222 | 223 | extern { 224 | pub fn uv_cancel(req: *mut uv_req_t) -> c_int; 225 | pub fn uv_req_size(type_: uv_req_type) -> size_t; 226 | } 227 | 228 | // timer.rst 229 | 230 | handle_struct!(uv_timer_t); 231 | pub type uv_timer_cb = extern "C" fn(*mut uv_timer_t); 232 | 233 | extern { 234 | pub fn uv_timer_init(loop_: *mut uv_loop_t, handle: *mut uv_timer_t) -> c_int; 235 | pub fn uv_timer_start(handle: *mut uv_timer_t, 236 | cb: uv_timer_cb, 237 | timeout: uint64_t, 238 | repeat: uint64_t) 239 | -> c_int; 240 | pub fn uv_timer_stop(handle: *mut uv_timer_t) -> c_int; 241 | pub fn uv_timer_again(handle: *mut uv_timer_t) -> c_int; 242 | pub fn uv_timer_set_repeat(handle: *mut uv_timer_t, repeat: uint64_t); 243 | pub fn uv_timer_get_repeat(handle: *const uv_timer_t) -> uint64_t; 244 | } 245 | 246 | // prepare.rst 247 | 248 | handle_struct!(uv_prepare_t); 249 | pub type uv_prepare_cb = extern "C" fn(*mut uv_prepare_t); 250 | 251 | extern { 252 | pub fn uv_prepare_init(loop_: *mut uv_loop_t, prepare: *mut uv_prepare_t) -> c_int; 253 | pub fn uv_prepare_start(prepare: *mut uv_prepare_t, cb: uv_prepare_cb) -> c_int; 254 | pub fn uv_prepare_stop(prepare: *mut uv_prepare_t) -> c_int; 255 | } 256 | 257 | // check.rst 258 | 259 | handle_struct!(uv_check_t); 260 | pub type uv_check_cb = extern "C" fn(*mut uv_check_t); 261 | 262 | extern { 263 | pub fn uv_check_init(loop_: *mut uv_loop_t, check: *mut uv_check_t) -> c_int; 264 | pub fn uv_check_start(check: *mut uv_check_t, cb: uv_check_cb) -> c_int; 265 | pub fn uv_check_stop(check: *mut uv_check_t) -> c_int; 266 | } 267 | 268 | // idle.rst 269 | 270 | handle_struct!(uv_idle_t); 271 | pub type uv_idle_cb = extern "C" fn(*mut uv_idle_t); 272 | 273 | extern { 274 | pub fn uv_idle_init(loop_: *mut uv_loop_t, idle: *mut uv_idle_t) -> c_int; 275 | pub fn uv_idle_start(idle: *mut uv_idle_t, cb: uv_idle_cb) -> c_int; 276 | pub fn uv_idle_stop(idle: *mut uv_idle_t) -> c_int; 277 | } 278 | 279 | // async.rst 280 | 281 | handle_struct!(uv_async_t); 282 | pub type uv_async_cb = extern "C" fn(*mut uv_async_t); 283 | 284 | extern { 285 | pub fn uv_async_init(loop_: *mut uv_loop_t, 286 | async: *mut uv_async_t, 287 | async_cb: uv_async_cb) 288 | -> c_int; 289 | pub fn uv_async_send(async: *mut uv_async_t) -> c_int; 290 | } 291 | 292 | // poll.rst 293 | 294 | handle_struct!(uv_poll_t); 295 | pub type uv_poll_cb = extern "C" fn(*mut uv_poll_t, c_int, c_int); 296 | 297 | #[repr(C)] 298 | pub enum uv_poll_event { 299 | UV_READABLE = 1, 300 | UV_WRITABLE = 2, 301 | UV_DISCONNECT = 4, 302 | } 303 | pub use uv_poll_event::*; 304 | 305 | extern { 306 | pub fn uv_poll_init(loop_: *mut uv_loop_t, handle: *mut uv_poll_t, fd: c_int) -> c_int; 307 | pub fn uv_poll_init_socket(loop_: *mut uv_loop_t, 308 | handle: *mut uv_poll_t, 309 | socket: uv_os_sock_t) 310 | -> c_int; 311 | pub fn uv_poll_start(handle: *mut uv_poll_t, events: c_int, cb: uv_poll_cb) -> c_int; 312 | pub fn uv_poll_stop(poll: *mut uv_poll_t) -> c_int; 313 | } 314 | 315 | // signal.rst 316 | 317 | #[repr(C)] 318 | pub struct uv_signal_t { 319 | pub data: *mut c_void, 320 | pub loop_: *mut uv_loop_t, // readonly 321 | pub type_: uv_handle_type, // readonly 322 | _h_private: [*mut c_void; 8], 323 | _flags: c_uint, 324 | _signal_cb: uv_signal_cb, 325 | pub signum: c_int, // readonly 326 | } 327 | pub type uv_signal_cb = extern "C" fn (*mut uv_signal_t, c_int); 328 | 329 | extern { 330 | pub fn uv_signal_init(loop_: *mut uv_loop_t, signal: *mut uv_signal_t) -> c_int; 331 | pub fn uv_signal_start(signal: *mut uv_signal_t, cb: uv_signal_cb, signum: c_int) -> c_int; 332 | pub fn uv_signal_stop(signal: *mut uv_signal_t) -> c_int; 333 | } 334 | 335 | // process.rst 336 | 337 | #[repr(C)] 338 | pub struct uv_process_t { 339 | pub data: *mut c_void, 340 | pub loop_: *mut uv_loop_t, // readonly 341 | pub type_: uv_handle_type, // readonly 342 | _h_private: [*mut c_void; 8], 343 | _flags: c_uint, 344 | _exit_cb: uv_exit_cb, 345 | pub pid: c_int, // readonly 346 | } 347 | pub type uv_exit_cb = extern "C" fn (*mut uv_process_t, int64_t, c_int); 348 | 349 | #[repr(C)] 350 | #[derive(Clone,Copy)] 351 | pub struct uv_process_options_t { 352 | pub exit_cb: uv_exit_cb, 353 | pub file: *const c_char, 354 | pub args: *mut *mut c_char, 355 | pub env: *mut *mut c_char, 356 | pub cwd: *const c_char, 357 | pub flags: c_uint, 358 | pub stdio_count: c_int, 359 | pub stdio: *mut uv_stdio_container_t, 360 | pub uid: uv_uid_t, 361 | pub gid: uv_gid_t, 362 | } 363 | 364 | #[repr(C)] 365 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 366 | pub enum uv_process_flags { 367 | UV_PROCESS_SETUID = (1 << 0), 368 | UV_PROCESS_SETGID = (1 << 1), 369 | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2), 370 | UV_PROCESS_DETACHED = (1 << 3), 371 | UV_PROCESS_WINDOWS_HIDE = (1 << 4), 372 | } 373 | 374 | #[repr(C)] 375 | #[derive(Clone,Copy)] 376 | pub struct uv_stdio_container_t { 377 | pub flags: uv_stdio_flags, 378 | pub stream: *mut uv_stream_t, // UNION 379 | } 380 | 381 | #[repr(C)] 382 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 383 | pub enum uv_stdio_flags { 384 | UV_IGNORE = 0x00, 385 | UV_CREATE_PIPE = 0x01, 386 | UV_INHERIT_FD = 0x02, 387 | UV_INHERIT_STREAM = 0x04, 388 | UV_READABLE_PIPE = 0x10, 389 | UV_WRITABLE_PIPE = 0x20, 390 | } 391 | 392 | extern { 393 | pub fn uv_disable_stdio_inheritance(); 394 | pub fn uv_spawn(loop_: *mut uv_loop_t, 395 | handle: *mut uv_process_t, 396 | options: *const uv_process_options_t) 397 | -> c_int; 398 | pub fn uv_process_kill(handle: *mut uv_process_t, signum: c_int) -> c_int; 399 | pub fn uv_kill(pid: c_int, signum: c_int) -> c_int; 400 | } 401 | 402 | // stream.rst 403 | 404 | #[cfg(windows)] 405 | #[repr(C)] 406 | struct uv_read_t { 407 | pub data: *mut c_void, 408 | pub loop_: *mut uv_loop_t, // readonly 409 | pub type_: uv_handle_type, // readonly 410 | _h_private: [*mut c_void; 8], 411 | _flags: c_uint, 412 | _event_handle: HANDLE, 413 | _wait_handle: HANDLE, 414 | } 415 | 416 | #[repr(C)] 417 | struct uv__work { 418 | _work: extern "C" fn(*mut uv__work), 419 | _done: extern "C" fn(*mut uv__work, c_int), 420 | _loop: *mut uv_loop_t, 421 | _wq: [*mut c_void; 2], 422 | } 423 | 424 | #[cfg(unix)] 425 | #[repr(C)] 426 | struct uv__io_t { 427 | _cb_queues: [*mut c_void; 5], 428 | _events_fds: [c_int; 3], 429 | #[cfg(any(target_os = "ios", target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly"))] 430 | _rwcount: [c_int; 2], 431 | } 432 | 433 | // this only works because it begins and ends with a pointer, so there will be 434 | // no extra padding from the nested struct 435 | #[repr(C)] 436 | struct _stream_private { 437 | _alloc_cb: uv_alloc_cb, 438 | _read_cb: uv_read_cb, 439 | 440 | #[cfg(windows)] 441 | _reqs_pending: c_uint, 442 | #[cfg(windows)] 443 | _activecnt: c_int, 444 | #[cfg(windows)] 445 | _read_req: uv_read_t, 446 | #[cfg(windows)] 447 | _u_stream_serv: [*mut c_void; 2], 448 | 449 | #[cfg(not(windows))] 450 | _connect_req: *mut c_void, 451 | #[cfg(not(windows))] 452 | _shutdown_req: *mut c_void, 453 | #[cfg(not(windows))] 454 | _io_watcher: uv__io_t, 455 | #[cfg(not(windows))] 456 | _write_queue: [*mut c_void; 2], 457 | #[cfg(not(windows))] 458 | _write_completed_queue: [*mut c_void; 2], 459 | #[cfg(not(windows))] 460 | _connection_cb: uv_connection_cb, 461 | #[cfg(not(windows))] 462 | _delayed_error: c_int, 463 | #[cfg(not(windows))] 464 | _accepted_fd: c_int, 465 | #[cfg(not(windows))] 466 | _queued_fds: *mut c_void, 467 | 468 | #[cfg(any(target_os = "ios", target_os = "macos"))] 469 | _select: *mut c_void, 470 | } 471 | 472 | macro_rules! stream_struct { 473 | ($name:ident) => { 474 | #[repr(C)] 475 | pub struct $name { 476 | pub data: *mut c_void, 477 | pub loop_: *mut uv_loop_t, // readonly 478 | pub type_: uv_handle_type, // readonly 479 | _h_private: [*mut c_void; 8], 480 | _flags: c_uint, 481 | pub write_queue_size: size_t, // readonly 482 | _s_private: _stream_private, 483 | } 484 | } 485 | } 486 | 487 | stream_struct!(uv_stream_t); 488 | #[repr(C)] 489 | pub struct uv_connect_t { 490 | pub data: *mut c_void, 491 | pub type_: uv_req_type, // readonly 492 | _r_private: _request_private, 493 | _cb: uv_connect_cb, 494 | pub handle: *mut uv_stream_t, // readonly 495 | } 496 | #[repr(C)] 497 | pub struct uv_shutdown_t { 498 | pub data: *mut c_void, 499 | pub type_: uv_req_type, // readonly 500 | _r_private: _request_private, 501 | pub handle: *mut uv_stream_t, // readonly 502 | _cb: uv_shutdown_cb, 503 | } 504 | #[repr(C)] 505 | pub struct uv_write_t { 506 | pub data: *mut c_void, 507 | pub type_: uv_req_type, // readonly 508 | _r_private: _request_private, 509 | _cb: uv_write_cb, 510 | pub send_handle: *mut uv_stream_t, 511 | pub handle: *mut uv_stream_t, 512 | } 513 | pub type uv_read_cb = extern "C" fn(*mut uv_stream_t, ssize_t, *const uv_buf_t); 514 | pub type uv_write_cb = extern "C" fn(*mut uv_write_t, c_int); 515 | pub type uv_connect_cb = extern "C" fn(*mut uv_connect_t, c_int); 516 | pub type uv_shutdown_cb = extern "C" fn(*mut uv_shutdown_t, c_int); 517 | pub type uv_connection_cb = extern "C" fn(*mut uv_stream_t, c_int); 518 | 519 | extern { 520 | pub fn uv_shutdown(req: *mut uv_shutdown_t, 521 | handle: *mut uv_stream_t, 522 | cb: uv_shutdown_cb) 523 | -> c_int; 524 | pub fn uv_listen(stream: *mut uv_stream_t, backlog: c_int, cb: uv_connection_cb) -> c_int; 525 | pub fn uv_accept(server: *mut uv_stream_t, client: *mut uv_stream_t) -> c_int; 526 | pub fn uv_read_start(stream: *mut uv_stream_t, 527 | alloc_cb: uv_alloc_cb, 528 | read_cb: uv_read_cb) 529 | -> c_int; 530 | pub fn uv_read_stop(stream: *mut uv_stream_t) -> c_int; 531 | pub fn uv_write(req: *mut uv_write_t, 532 | handle: *mut uv_stream_t, 533 | bufs: *const uv_buf_t, 534 | nbufs: c_uint, 535 | cb: uv_write_cb) 536 | -> c_int; 537 | pub fn uv_write2(req: *mut uv_write_t, 538 | handle: *mut uv_stream_t, 539 | bufs: *const uv_buf_t, 540 | nbufs: c_uint, 541 | send_handle: *mut uv_stream_t, 542 | cb: uv_write_cb) 543 | -> c_int; 544 | pub fn uv_try_write(handle: *mut uv_stream_t, bufs: *const uv_buf_t, nbufs: c_uint) -> c_int; 545 | pub fn uv_is_readable(handle: *const uv_stream_t) -> c_int; 546 | pub fn uv_is_writable(handle: *const uv_stream_t) -> c_int; 547 | pub fn uv_stream_set_blocking(handle: *mut uv_stream_t, blocking: c_int) -> c_int; 548 | } 549 | 550 | // tcp.rst 551 | 552 | #[repr(C)] 553 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 554 | pub enum uv_tcp_flags { 555 | UV_TCP_IPV6ONLY = 1, 556 | } 557 | pub use uv_tcp_flags::*; 558 | 559 | #[repr(C)] 560 | pub struct uv_tcp_t { 561 | pub data: *mut c_void, 562 | pub loop_: *mut uv_loop_t, // readonly 563 | pub type_: uv_handle_type, // readonly 564 | _h_private: [*mut c_void; 8], 565 | _flags: c_uint, 566 | pub write_queue_size: size_t, // readonly 567 | _s_private: _stream_private, 568 | #[cfg(windows)] 569 | _tcp_private: [*mut c_void; 6], 570 | } 571 | 572 | extern { 573 | pub fn uv_tcp_init(loop_: *mut uv_loop_t, handle: *mut uv_tcp_t) -> c_int; 574 | pub fn uv_tcp_init_ex(loop_: *mut uv_loop_t, handle: *mut uv_tcp_t, flags: c_uint) -> c_int; 575 | pub fn uv_tcp_open(handle: *mut uv_tcp_t, sock: uv_os_sock_t) -> c_int; 576 | pub fn uv_tcp_nodelay(handle: *mut uv_tcp_t, enable: c_int) -> c_int; 577 | pub fn uv_tcp_keepalive(handle: *mut uv_tcp_t, enable: c_int, delay: c_uint) -> c_int; 578 | pub fn uv_tcp_simultaneous_accepts(handle: *mut uv_tcp_t, enable: c_int) -> c_int; 579 | pub fn uv_tcp_bind(handle: *mut uv_tcp_t, addr: *const sockaddr, flags: c_uint) -> c_int; 580 | pub fn uv_tcp_getsockname(handle: *const uv_tcp_t, 581 | name: *mut sockaddr, 582 | namelen: *mut c_int) 583 | -> c_int; 584 | pub fn uv_tcp_getpeername(handle: *const uv_tcp_t, 585 | name: *mut sockaddr, 586 | namelen: *mut c_int) 587 | -> c_int; 588 | pub fn uv_tcp_connect(req: *mut uv_connect_t, 589 | handle: *mut uv_tcp_t, 590 | addr: *const sockaddr, 591 | cb: uv_connect_cb) 592 | -> c_int; 593 | } 594 | 595 | // pipe.rst 596 | 597 | stream_struct!(uv_pipe_t); 598 | 599 | extern { 600 | pub fn uv_pipe_init(loop_: *mut uv_loop_t, handle: *mut uv_pipe_t, ipc: c_int) -> c_int; 601 | pub fn uv_pipe_open(handle: *mut uv_pipe_t, file: uv_file) -> c_int; 602 | pub fn uv_pipe_bind(handle: *mut uv_pipe_t, name: *const c_char) -> c_int; 603 | pub fn uv_pipe_connect(req: *mut uv_connect_t, 604 | handle: *mut uv_pipe_t, 605 | name: *const c_char, 606 | cb: uv_connect_cb); 607 | pub fn uv_pipe_getsockname(handle: *const uv_pipe_t, 608 | buffer: *mut c_char, 609 | size: *mut size_t) 610 | -> c_int; 611 | pub fn uv_pipe_getpeername(handle: *const uv_pipe_t, 612 | buffer: *mut c_char, 613 | size: *mut size_t) 614 | -> c_int; 615 | pub fn uv_pipe_pending_instances(handle: *mut uv_pipe_t, count: c_int); 616 | pub fn uv_pipe_pending_count(handle: *mut uv_pipe_t) -> c_int; 617 | pub fn uv_pipe_pending_type(handle: *mut uv_pipe_t) -> uv_handle_type; 618 | } 619 | 620 | // tty.rst 621 | 622 | stream_struct!(uv_tty_t); 623 | #[repr(C)] 624 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 625 | pub enum uv_tty_mode_t { 626 | UV_TTY_MODE_NORMAL = 0, 627 | UV_TTY_MODE_RAW = 1, 628 | UV_TTY_MODE_IO = 2, 629 | } 630 | pub use uv_tty_mode_t::*; 631 | 632 | extern { 633 | pub fn uv_tty_init(loop_: *mut uv_loop_t, 634 | handle: *mut uv_tty_t, 635 | fd: uv_file, 636 | readable: c_int) 637 | -> c_int; 638 | pub fn uv_tty_set_mode(handle: *mut uv_tty_t, mode: uv_tty_mode_t) -> c_int; 639 | pub fn uv_tty_reset_mode() -> c_int; 640 | pub fn uv_tty_get_winsize(handle: *mut uv_tty_t, 641 | width: *mut c_int, 642 | height: *mut c_int) 643 | -> c_int; 644 | } 645 | 646 | // udp.rst 647 | 648 | #[repr(C)] 649 | pub struct uv_udp_t { 650 | pub data: *mut c_void, 651 | pub loop_: *mut uv_loop_t, // readonly 652 | pub type_: uv_handle_type, // readonly 653 | _h_private: [*mut c_void; 8], 654 | _flags: c_uint, 655 | pub send_queue_size: size_t, // readonly 656 | pub send_queue_count: size_t, // readonly 657 | } 658 | #[repr(C)] 659 | pub struct uv_udp_send_t { 660 | pub data: *mut c_void, 661 | pub type_: uv_req_type, // readonly 662 | _r_private: _request_private, 663 | pub handle: *mut uv_udp_t, // readonly 664 | _cb: uv_udp_send_cb, 665 | } 666 | #[repr(C)] 667 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 668 | pub enum uv_udp_flags { 669 | UV_UDP_IPV6ONLY = 1, 670 | UV_UDP_PARTIAL = 2, 671 | UV_UDP_REUSEADDR = 4, 672 | } 673 | pub use uv_udp_flags::*; 674 | pub type uv_udp_send_cb = extern "C" fn(*mut uv_udp_send_t, c_int); 675 | pub type uv_udp_recv_cb = extern "C" fn(*mut uv_udp_t, ssize_t, *const uv_buf_t, *const sockaddr, c_uint); 676 | #[repr(C)] 677 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 678 | pub enum uv_membership { 679 | UV_LEAVE_GROUP = 0, 680 | UV_JOIN_GROUP = 1, 681 | } 682 | pub use uv_membership::*; 683 | 684 | extern { 685 | pub fn uv_udp_init(loop_: *mut uv_loop_t, handle: *mut uv_udp_t) -> c_int; 686 | pub fn uv_udp_init_ex(loop_: *mut uv_loop_t, handle: *mut uv_udp_t, flags: c_uint) -> c_int; 687 | pub fn uv_udp_open(handle: *mut uv_udp_t, sock: uv_os_sock_t) -> c_int; 688 | pub fn uv_udp_bind(handle: *mut uv_udp_t, addr: *const sockaddr, flags: c_uint) -> c_int; 689 | pub fn uv_udp_getsockname(handle: *const uv_udp_t, 690 | name: *mut sockaddr, 691 | namelen: *mut c_int) 692 | -> c_int; 693 | pub fn uv_udp_set_membership(handle: *mut uv_udp_t, 694 | multicast_addr: *const c_char, 695 | interface_addr: *const c_char, 696 | membership: uv_membership) 697 | -> c_int; 698 | pub fn uv_udp_set_multicast_loop(handle: *mut uv_udp_t, on: c_int) -> c_int; 699 | pub fn uv_udp_set_multicast_ttl(handle: *mut uv_udp_t, ttl: c_int) -> c_int; 700 | pub fn uv_udp_set_multicast_interface(handle: *mut uv_udp_t, 701 | interface_addr: *const c_char) 702 | -> c_int; 703 | pub fn uv_udp_set_broadcast(handle: *mut uv_udp_t, on: c_int) -> c_int; 704 | pub fn uv_udp_set_ttl(handle: *mut uv_udp_t, ttl: c_int) -> c_int; 705 | pub fn uv_udp_send(req: *mut uv_udp_send_t, 706 | handle: *mut uv_udp_t, 707 | bufs: *const uv_buf_t, 708 | nbufs: c_uint, 709 | addr: *const sockaddr, 710 | send_cb: uv_udp_send_cb) 711 | -> c_int; 712 | pub fn uv_udp_try_send(handle: *mut uv_udp_t, 713 | bufs: *const uv_buf_t, 714 | nbufs: c_uint, 715 | addr: *const sockaddr) 716 | -> c_int; 717 | pub fn uv_udp_recv_start(handle: *mut uv_udp_t, 718 | alloc_cb: uv_alloc_cb, 719 | recv_cb: uv_udp_recv_cb) 720 | -> c_int; 721 | pub fn uv_udp_recv_stop(handle: *mut uv_udp_t) -> c_int; 722 | } 723 | 724 | // fs_event.rst 725 | 726 | handle_struct!(uv_fs_event_t); 727 | pub type uv_fs_event_cb = extern "C" fn(*mut uv_fs_event_t, *const c_char, c_int, c_int); 728 | #[repr(C)] 729 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 730 | pub enum uv_fs_event { 731 | UV_RENAME = 1, 732 | UV_CHANGE = 2, 733 | } 734 | pub use uv_fs_event::*; 735 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 736 | #[repr(C)] 737 | pub enum uv_fs_event_flags { 738 | UV_FS_EVENT_WATCH_ENTRY = 1, 739 | UV_FS_EVENT_STAT = 2, 740 | UV_FS_EVENT_RECURSIVE = 4, 741 | } 742 | pub use uv_fs_event_flags::*; 743 | 744 | extern { 745 | pub fn uv_fs_event_init(loop_: *mut uv_loop_t, handle: *mut uv_fs_event_t) -> c_int; 746 | pub fn uv_fs_event_start(handle: *mut uv_fs_event_t, 747 | cb: uv_fs_event_cb, 748 | path: *const c_char, 749 | flags: c_uint) 750 | -> c_int; 751 | pub fn uv_fs_event_stop(handle: *mut uv_fs_event_t) -> c_int; 752 | pub fn uv_fs_event_getpath(handle: *mut uv_fs_event_t, 753 | buffer: *mut c_char, 754 | size: *mut size_t) 755 | -> c_int; 756 | } 757 | 758 | // fs_poll.rst 759 | 760 | handle_struct!(uv_fs_poll_t); 761 | pub type uv_fs_poll_cb = extern "C" fn(*mut uv_fs_poll_t, c_int, *const uv_stat_t, *const uv_stat_t); 762 | 763 | extern { 764 | pub fn uv_fs_poll_init(loop_: *mut uv_loop_t, handle: *mut uv_fs_poll_t) -> c_int; 765 | pub fn uv_fs_poll_start(handle: *mut uv_fs_poll_t, 766 | poll_cb: uv_fs_poll_cb, 767 | path: *const c_char, 768 | interval: c_uint) 769 | -> c_int; 770 | pub fn uv_fs_poll_stop(handle: *mut uv_fs_poll_t) -> c_int; 771 | pub fn uv_fs_poll_getpath(handle: *mut uv_fs_poll_t, 772 | buffer: *mut c_char, 773 | size: *mut size_t) 774 | -> c_int; 775 | } 776 | 777 | // fs.rst 778 | 779 | #[repr(C)] 780 | pub struct uv_fs_t { 781 | pub data: *mut c_void, 782 | pub type_: uv_req_type, // readonly 783 | _r_private: _request_private, 784 | pub fs_type: uv_fs_type, 785 | pub loop_: *mut uv_loop_t, 786 | _cb: uv_fs_cb, 787 | pub result: ssize_t, 788 | pub ptr: *mut c_void, 789 | pub path: *const c_char, 790 | pub statbuf: uv_stat_t, 791 | } 792 | 793 | #[repr(C)] 794 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 795 | pub struct uv_timespec_t { 796 | pub tv_sec: c_long, 797 | pub tv_nsec: c_long, 798 | } 799 | 800 | #[repr(C)] 801 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 802 | pub struct uv_stat_t { 803 | pub st_dev: uint64_t, 804 | pub st_mode: uint64_t, 805 | pub st_nlink: uint64_t, 806 | pub st_uid: uint64_t, 807 | pub st_gid: uint64_t, 808 | pub st_rdev: uint64_t, 809 | pub st_ino: uint64_t, 810 | pub st_size: uint64_t, 811 | pub st_blksize: uint64_t, 812 | pub st_blocks: uint64_t, 813 | pub st_flags: uint64_t, 814 | pub st_gen: uint64_t, 815 | pub st_atim: uv_timespec_t, 816 | pub st_mtim: uv_timespec_t, 817 | pub st_ctim: uv_timespec_t, 818 | pub st_birthtim: uv_timespec_t, 819 | } 820 | 821 | #[repr(C)] 822 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 823 | pub enum uv_fs_type { 824 | UV_FS_UNKNOWN = -1, 825 | UV_FS_CUSTOM = 0, 826 | UV_FS_OPEN = 1, 827 | UV_FS_CLOSE = 2, 828 | UV_FS_READ = 3, 829 | UV_FS_WRITE = 4, 830 | UV_FS_SENDFILE = 5, 831 | UV_FS_STAT = 6, 832 | UV_FS_LSTAT = 7, 833 | UV_FS_FSTAT = 8, 834 | UV_FS_FTRUNCATE = 9, 835 | UV_FS_UTIME = 10, 836 | UV_FS_FUTIME = 11, 837 | UV_FS_ACCESS = 12, 838 | UV_FS_CHMOD = 13, 839 | UV_FS_FCHMOD = 14, 840 | UV_FS_FSYNC = 15, 841 | UV_FS_FDATASYNC = 16, 842 | UV_FS_UNLINK = 17, 843 | UV_FS_RMDIR = 18, 844 | UV_FS_MKDIR = 19, 845 | UV_FS_MKDTEMP = 20, 846 | UV_FS_RENAME = 21, 847 | UV_FS_SCANDIR = 22, 848 | UV_FS_LINK = 23, 849 | UV_FS_SYMLINK = 24, 850 | UV_FS_READLINK = 25, 851 | UV_FS_CHOWN = 26, 852 | UV_FS_FCHOWN = 27, 853 | UV_FS_REALPATH = 28, 854 | } 855 | pub use uv_fs_type::*; 856 | 857 | #[repr(C)] 858 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 859 | pub enum uv_dirent_type_t { 860 | UV_DIRENT_UNKNOWN = 0, 861 | UV_DIRENT_FILE = 1, 862 | UV_DIRENT_DIR = 2, 863 | UV_DIRENT_LINK = 3, 864 | UV_DIRENT_FIFO = 4, 865 | UV_DIRENT_SOCKET = 5, 866 | UV_DIRENT_CHAR = 6, 867 | UV_DIRENT_BLOCK = 7, 868 | } 869 | pub use uv_dirent_type_t::*; 870 | 871 | #[repr(C)] 872 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 873 | pub struct uv_dirent_t { 874 | pub name: *const c_char, 875 | pub type_: uv_dirent_type_t, 876 | } 877 | 878 | pub const UV_FS_SYMLINK_DIR: c_int = 0x0001; 879 | pub const UV_FS_SYMLINK_JUNCTION: c_int = 0x0002; 880 | 881 | pub type uv_fs_cb = Option; 882 | 883 | extern { 884 | pub fn uv_fs_req_cleanup(req: *mut uv_fs_t); 885 | pub fn uv_fs_close(loop_: *mut uv_loop_t, 886 | req: *mut uv_fs_t, 887 | file: uv_file, 888 | cb: uv_fs_cb) 889 | -> c_int; 890 | pub fn uv_fs_open(loop_: *mut uv_loop_t, 891 | req: *mut uv_fs_t, 892 | path: *const c_char, 893 | flags: c_int, 894 | mode: c_int, 895 | cb: uv_fs_cb) 896 | -> c_int; 897 | pub fn uv_fs_read(loop_: *mut uv_loop_t, 898 | req: *mut uv_fs_t, 899 | file: uv_file, 900 | bufs: *const uv_buf_t, 901 | nbufs: c_uint, 902 | offset: int64_t, 903 | cb: uv_fs_cb) 904 | -> c_int; 905 | pub fn uv_fs_unlink(loop_: *mut uv_loop_t, 906 | req: *mut uv_fs_t, 907 | path: *const c_char, 908 | cb: uv_fs_cb) 909 | -> c_int; 910 | pub fn uv_fs_write(loop_: *mut uv_loop_t, 911 | req: *mut uv_fs_t, 912 | file: uv_file, 913 | bufs: *const uv_buf_t, 914 | nbufs: c_uint, 915 | offset: int64_t, 916 | cb: uv_fs_cb) 917 | -> c_int; 918 | pub fn uv_fs_mkdir(loop_: *mut uv_loop_t, 919 | req: *mut uv_fs_t, 920 | path: *const c_char, 921 | mode: c_int, 922 | cb: uv_fs_cb) 923 | -> c_int; 924 | pub fn uv_fs_mkdtemp(loop_: *mut uv_loop_t, 925 | req: *mut uv_fs_t, 926 | tpl: *const c_char, 927 | cb: uv_fs_cb) 928 | -> c_int; 929 | pub fn uv_fs_rmdir(loop_: *mut uv_loop_t, 930 | req: *mut uv_fs_t, 931 | path: *const c_char, 932 | cb: uv_fs_cb) 933 | -> c_int; 934 | pub fn uv_fs_scandir(loop_: *mut uv_loop_t, 935 | req: *mut uv_fs_t, 936 | path: *const c_char, 937 | flags: c_int, 938 | cb: uv_fs_cb) 939 | -> c_int; 940 | pub fn uv_fs_scandir_next(req: *mut uv_fs_t, ent: *mut uv_dirent_t) -> c_int; 941 | pub fn uv_fs_stat(loop_: *mut uv_loop_t, 942 | req: *mut uv_fs_t, 943 | path: *const c_char, 944 | cb: uv_fs_cb) 945 | -> c_int; 946 | pub fn uv_fs_fstat(loop_: *mut uv_loop_t, 947 | req: *mut uv_fs_t, 948 | file: uv_file, 949 | cb: uv_fs_cb) 950 | -> c_int; 951 | pub fn uv_fs_lstat(loop_: *mut uv_loop_t, 952 | req: *mut uv_fs_t, 953 | path: *const c_char, 954 | cb: uv_fs_cb) 955 | -> c_int; 956 | pub fn uv_fs_rename(loop_: *mut uv_loop_t, 957 | req: *mut uv_fs_t, 958 | path: *const c_char, 959 | new_path: *const c_char, 960 | cb: uv_fs_cb) 961 | -> c_int; 962 | pub fn uv_fs_fsync(loop_: *mut uv_loop_t, 963 | req: *mut uv_fs_t, 964 | file: uv_file, 965 | cb: uv_fs_cb) 966 | -> c_int; 967 | pub fn uv_fs_fdatasync(loop_: *mut uv_loop_t, 968 | req: *mut uv_fs_t, 969 | file: uv_file, 970 | cb: uv_fs_cb) 971 | -> c_int; 972 | pub fn uv_fs_ftruncate(loop_: *mut uv_loop_t, 973 | req: *mut uv_fs_t, 974 | file: uv_file, 975 | offset: int64_t, 976 | cb: uv_fs_cb) 977 | -> c_int; 978 | pub fn uv_fs_sendfile(loop_: *mut uv_loop_t, 979 | req: *mut uv_fs_t, 980 | out_fd: uv_file, 981 | in_fd: uv_file, 982 | in_offset: int64_t, 983 | length: size_t, 984 | cb: uv_fs_cb) 985 | -> c_int; 986 | pub fn uv_fs_access(loop_: *mut uv_loop_t, 987 | req: *mut uv_fs_t, 988 | path: *const c_char, 989 | mode: c_int, 990 | cb: uv_fs_cb) 991 | -> c_int; 992 | pub fn uv_fs_chmod(loop_: *mut uv_loop_t, 993 | req: *mut uv_fs_t, 994 | path: *const c_char, 995 | mode: c_int, 996 | cb: uv_fs_cb) 997 | -> c_int; 998 | pub fn uv_fs_fchmod(loop_: *mut uv_loop_t, 999 | req: *mut uv_fs_t, 1000 | file: uv_file, 1001 | mode: c_int, 1002 | cb: uv_fs_cb) 1003 | -> c_int; 1004 | pub fn uv_fs_utime(loop_: *mut uv_loop_t, 1005 | req: *mut uv_fs_t, 1006 | path: *const c_char, 1007 | atime: f64, 1008 | mtime: f64, 1009 | cb: uv_fs_cb) 1010 | -> c_int; 1011 | pub fn uv_fs_futime(loop_: *mut uv_loop_t, 1012 | req: *mut uv_fs_t, 1013 | file: uv_file, 1014 | atime: f64, 1015 | mtime: f64, 1016 | cb: uv_fs_cb) 1017 | -> c_int; 1018 | pub fn uv_fs_link(loop_: *mut uv_loop_t, 1019 | req: *mut uv_fs_t, 1020 | path: *const c_char, 1021 | new_path: *const c_char, 1022 | cb: uv_fs_cb) 1023 | -> c_int; 1024 | pub fn uv_fs_symlink(loop_: *mut uv_loop_t, 1025 | req: *mut uv_fs_t, 1026 | path: *const c_char, 1027 | new_path: *const c_char, 1028 | flags: c_int, 1029 | cb: uv_fs_cb) 1030 | -> c_int; 1031 | pub fn uv_fs_readlink(loop_: *mut uv_loop_t, 1032 | req: *mut uv_fs_t, 1033 | path: *const c_char, 1034 | cb: uv_fs_cb) 1035 | -> c_int; 1036 | pub fn uv_fs_chown(loop_: *mut uv_loop_t, 1037 | req: *mut uv_fs_t, 1038 | path: *const c_char, 1039 | uid: uv_uid_t, 1040 | gid: uv_gid_t, 1041 | cb: uv_fs_cb) 1042 | -> c_int; 1043 | pub fn uv_fs_fchown(loop_: *mut uv_loop_t, 1044 | req: *mut uv_fs_t, 1045 | file: uv_file, 1046 | uid: uv_uid_t, 1047 | gid: uv_gid_t, 1048 | cb: uv_fs_cb) 1049 | -> c_int; 1050 | pub fn uv_fs_realpath(loop_: *mut uv_loop_t, 1051 | req: *mut uv_fs_t, 1052 | path: *const c_char, 1053 | cb: uv_fs_cb) 1054 | -> c_int; 1055 | } 1056 | 1057 | // passwd.rst 1058 | 1059 | #[repr(C)] 1060 | pub struct uv_passwd_t { 1061 | pub username: *mut c_char, 1062 | pub uid: c_long, 1063 | pub gid: c_long, 1064 | pub shell: *mut c_char, 1065 | pub homedir: *mut c_char, 1066 | } 1067 | 1068 | extern { 1069 | pub fn uv_os_get_passwd(passwd: *mut uv_passwd_t) -> c_int; 1070 | pub fn uv_os_free_passwd(passwd: *mut uv_passwd_t); 1071 | } 1072 | 1073 | 1074 | // threadpool.rst 1075 | 1076 | #[repr(C)] 1077 | pub struct uv_work_t { 1078 | pub data: *mut c_void, 1079 | pub type_: uv_req_type, // readonly 1080 | _r_private: _request_private, 1081 | pub loop_: *mut uv_loop_t, 1082 | _work_cb: uv_work_cb, 1083 | _after_work_cb: uv_after_work_cb, 1084 | } 1085 | pub type uv_work_cb = extern "C" fn(*mut uv_work_t); 1086 | pub type uv_after_work_cb = extern "C" fn(*mut uv_work_t, c_int); 1087 | 1088 | extern { 1089 | pub fn uv_queue_work(loop_: *mut uv_loop_t, 1090 | req: *mut uv_work_t, 1091 | work_cb: uv_work_cb, 1092 | after_work_cb: uv_after_work_cb) 1093 | -> c_int; 1094 | } 1095 | 1096 | // dns.rst 1097 | 1098 | #[repr(C)] 1099 | pub struct uv_getaddrinfo_t { 1100 | pub data: *mut c_void, 1101 | pub type_: uv_req_type, // readonly 1102 | _r_private: _request_private, 1103 | pub loop_: *mut uv_loop_t, 1104 | _work_req: uv__work, 1105 | _cb: uv_getaddrinfo_cb, 1106 | 1107 | #[cfg(unix)] 1108 | _hints: *mut addrinfo, 1109 | #[cfg(unix)] 1110 | _hostname: *mut c_char, 1111 | #[cfg(unix)] 1112 | _service: *mut c_char, 1113 | #[cfg(unix)] 1114 | pub addrinfo: *mut addrinfo, 1115 | #[cfg(unix)] 1116 | _retcode: c_int, 1117 | 1118 | #[cfg(windows)] 1119 | _alloc: *mut c_void, 1120 | #[cfg(windows)] 1121 | _node: *mut c_void, 1122 | #[cfg(windows)] 1123 | _service: *mut c_void, 1124 | #[cfg(windows)] 1125 | _addrinfow: *mut c_void, 1126 | #[cfg(windows)] 1127 | addrinfo: *mut addrinfo, 1128 | #[cfg(windows)] 1129 | _retcode: c_int, 1130 | } 1131 | 1132 | pub type uv_getaddrinfo_cb = Option; 1133 | 1134 | #[repr(C)] 1135 | pub struct uv_getnameinfo_t { 1136 | pub data: *mut c_void, 1137 | pub type_: uv_req_type, // readonly 1138 | _r_private: _request_private, 1139 | pub loop_: *mut uv_loop_t, 1140 | _work_req: uv__work, 1141 | _getnameinfo_cb: uv_getnameinfo_cb, 1142 | _storage: sockaddr_storage, 1143 | _flags: c_int, 1144 | // RFC 2553 gives these constants. Unclear how portable they are 1145 | pub host: [c_char; 1025], 1146 | pub service: [c_char; 32], 1147 | _retcode: c_int, 1148 | } 1149 | 1150 | pub type uv_getnameinfo_cb = Option; 1151 | 1152 | extern { 1153 | pub fn uv_getaddrinfo(loop_: *mut uv_loop_t, 1154 | req: *mut uv_getaddrinfo_t, 1155 | getaddrinfo_cb: uv_getaddrinfo_cb, 1156 | node: *const c_char, 1157 | service: *const c_char, 1158 | hints: *const addrinfo) 1159 | -> c_int; 1160 | pub fn uv_freeaddrint(ai: *mut addrinfo); 1161 | pub fn uv_getnameinfo(loop_: *mut uv_loop_t, 1162 | req: *mut uv_getnameinfo_t, 1163 | getnameinfo_cb: uv_getnameinfo_cb, 1164 | addr: *const sockaddr, 1165 | flags: c_int) 1166 | -> c_int; 1167 | } 1168 | 1169 | // dll.rst 1170 | 1171 | #[repr(C)] 1172 | pub struct uv_lib_t { 1173 | _handle: *mut c_void, // HMODULE is a typedef for void*, so this works on both platforms 1174 | _errmst: *mut c_char, 1175 | } 1176 | 1177 | extern { 1178 | pub fn uv_dlopen(filename: *const c_char, lib: *mut uv_lib_t) -> c_int; 1179 | pub fn uv_dlclose(lib: *mut uv_lib_t); 1180 | pub fn uv_dlsym(lib: *mut uv_lib_t, name: *const c_char, ptr: *mut *mut c_void) -> c_int; 1181 | pub fn uv_dlerror(lib: *const uv_lib_t) -> *const c_char; 1182 | } 1183 | 1184 | // threading.rst 1185 | 1186 | // Not bound because the types differ widely between platforms and it's 1187 | // thoroughly redundant with native Rust threading 1188 | 1189 | // misc.rst 1190 | 1191 | pub type uv_malloc_func = extern "C" fn(size_t) -> *mut c_void; 1192 | pub type uv_realloc_func = extern "C" fn(*mut c_void, size_t) -> *mut c_void; 1193 | pub type uv_calloc_func = extern "C" fn(size_t, size_t) -> *mut c_void; 1194 | pub type uv_free_func = extern "C" fn(*mut c_void); 1195 | 1196 | pub type uv_file = c_int; 1197 | 1198 | #[repr(C)] 1199 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 1200 | pub struct uv_rusage_t { 1201 | pub ru_utime: uv_timeval_t, 1202 | pub ru_stime: uv_timeval_t, 1203 | pub ru_maxrss: uint64_t, 1204 | pub ru_ixrss: uint64_t, 1205 | pub ru_idrss: uint64_t, 1206 | pub ru_isrss: uint64_t, 1207 | pub ru_minflt: uint64_t, 1208 | pub ru_majflt: uint64_t, 1209 | pub ru_nswap: uint64_t, 1210 | pub ru_inblock: uint64_t, 1211 | pub ru_oublock: uint64_t, 1212 | pub ru_msgsnd: uint64_t, 1213 | pub ru_msgrcv: uint64_t, 1214 | pub ru_nsignals: uint64_t, 1215 | pub ru_nvcsw: uint64_t, 1216 | pub ru_nivcsw: uint64_t, 1217 | } 1218 | 1219 | #[repr(C)] 1220 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 1221 | pub struct uv_cpu_times_t { 1222 | pub user: uint64_t, 1223 | pub nice: uint64_t, 1224 | pub sys: uint64_t, 1225 | pub idle: uint64_t, 1226 | pub irq: uint64_t, 1227 | } 1228 | 1229 | #[repr(C)] 1230 | #[derive(Debug,Clone,Copy,PartialEq,Eq)] 1231 | pub struct uv_cpu_info_t { 1232 | pub model: *mut c_char, 1233 | pub speed: c_int, 1234 | pub cpu_times: uv_cpu_times_t, 1235 | } 1236 | 1237 | #[repr(C)] 1238 | #[derive(Clone,Copy)] 1239 | pub struct uv_interface_address_t { 1240 | pub name: *mut c_char, 1241 | pub phys_addr: [c_char; 6], 1242 | pub is_internal: c_int, 1243 | pub u_address: sockaddr_in6, // UNION 1244 | pub u_netmask: sockaddr_in6, // UNION 1245 | } 1246 | 1247 | extern { 1248 | pub fn uv_guess_handle(file: uv_file) -> uv_handle_type; 1249 | pub fn uv_replace_allocator(malloc_func: uv_malloc_func, 1250 | realloc_func: uv_realloc_func, 1251 | calloc_func: uv_calloc_func, 1252 | free_func: uv_free_func) 1253 | -> c_int; 1254 | pub fn uv_buf_init(base: *mut c_char, len: c_uint) -> uv_buf_t; 1255 | pub fn uv_setup_args(argc: c_int, argv: *mut *mut c_char) -> *mut *mut c_char; 1256 | pub fn uv_get_process_title(buffer: *mut c_char, size: size_t) -> c_int; 1257 | pub fn uv_set_process_title(title: *const c_char) -> c_int; 1258 | pub fn uv_resident_set_memory(rss: *mut size_t) -> c_int; 1259 | pub fn uv_uptime(uptime: *mut f64) -> c_int; 1260 | pub fn uv_getrusage(rusage: *mut uv_rusage_t) -> c_int; 1261 | pub fn uv_cpu_info(cpu_infos: *mut *mut uv_cpu_info_t, count: *mut c_int) -> c_int; 1262 | pub fn uv_free_cpu_info(cpu_infos: *mut uv_cpu_info_t, count: c_int); 1263 | pub fn uv_interface_addresses(addresses: *mut *mut uv_interface_address_t, 1264 | count: *mut c_int) 1265 | -> c_int; 1266 | pub fn uv_free_interface_addresses(addresses: *mut uv_interface_address_t, count: c_int); 1267 | pub fn uv_loadavg(avg: *mut [f64; 3]); 1268 | pub fn uv_ip4_addr(ip: *const c_char, port: c_int, addr: *mut sockaddr_in) -> c_int; 1269 | pub fn uv_ip6_addr(ip: *const c_char, port: c_int, addr: *mut sockaddr_in6) -> c_int; 1270 | pub fn uv_ip4_name(src: *const sockaddr_in, dst: *mut c_char, size: size_t) -> c_int; 1271 | pub fn uv_ip6_name(src: *const sockaddr_in6, dst: *mut c_char, size: size_t) -> c_int; 1272 | pub fn uv_inet_ntop(af: c_int, src: *const c_void, dst: *mut c_char, size: size_t) -> c_int; 1273 | pub fn uv_inet_pton(af: c_int, src: *const c_char, dst: *mut c_void) -> c_int; 1274 | pub fn uv_exepath(buffer: *mut c_char, size: *mut size_t) -> c_int; 1275 | pub fn uv_cwd(buffer: *mut c_char, size: *mut size_t) -> c_int; 1276 | pub fn uv_chdir(dir: *const c_char) -> c_int; 1277 | pub fn uv_os_homedir(buffer: *mut c_char, size: *mut size_t) -> c_int; 1278 | pub fn uv_os_tmpdir(buffer: *mut c_char, size: *mut size_t) -> c_int; 1279 | pub fn uv_get_free_memory() -> uint64_t; 1280 | pub fn uv_get_total_memory() -> uint64_t; 1281 | pub fn uv_hrtime() -> uint64_t; 1282 | } 1283 | 1284 | #[cfg(test)] 1285 | mod test { 1286 | use super::*; 1287 | use std::mem; 1288 | macro_rules! testfun { 1289 | ($name:ident : $($code:stmt ; )*) => { #[test] fn $name() { unsafe { $( $code; )* } } } 1290 | } 1291 | testfun! { smoke: assert!(uv_version() >= 0x10705); } 1292 | testfun! { handle_size: assert_eq!(uv_handle_size(UV_HANDLE) as usize, mem::size_of::()); } 1293 | testfun! { stream_size: assert_eq!(uv_handle_size(UV_STREAM) as usize, mem::size_of::()); } 1294 | testfun! { tcp_size: assert_eq!(uv_handle_size(UV_TCP) as usize, mem::size_of::()); } 1295 | testfun! { req_size: assert_eq!(uv_req_size(UV_REQ) as usize, mem::size_of::()); } 1296 | testfun! { gai_size: assert_eq!(uv_req_size(UV_GETADDRINFO) as usize, mem::size_of::()); } 1297 | testfun! { gni_size: assert_eq!(uv_req_size(UV_GETNAMEINFO) as usize, mem::size_of::()); } 1298 | } 1299 | -------------------------------------------------------------------------------- /libuv/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libuv" 3 | version = "0.1.0" 4 | authors = ["Stefan O'Rear "] 5 | repository = "https://github.com/sorear/libuv-rs" 6 | description = "Multiplexed I/O using libuv" 7 | keywords = ["uv","epoll","iocp","select"] 8 | license = "MIT" 9 | 10 | [dependencies] 11 | libuv-sys = "0.1.0" 12 | -------------------------------------------------------------------------------- /libuv/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate libuv_sys; 2 | use std::ffi::CStr; 3 | 4 | pub fn version_hex() -> u32 { 5 | unsafe { libuv_sys::uv_version() as u32 } 6 | } 7 | 8 | pub fn version_string() -> &'static str { 9 | unsafe { CStr::from_ptr(libuv_sys::uv_version_string()).to_str().unwrap() } 10 | } 11 | 12 | #[cfg(test)] 13 | mod tests { 14 | use super::*; 15 | #[test] 16 | fn test_version_hex() { 17 | assert_eq!(version_hex(), 0x10901); 18 | } 19 | 20 | #[test] 21 | fn test_version_string() { 22 | assert_eq!(version_string(), "1.9.1"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /thread-bound/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thread-bound" 3 | version = "0.1.0" 4 | authors = ["Stefan O'Rear "] 5 | repository = "https://github.com/sorear/libuv-rs" 6 | description = "Variables which can only be accessed by one thread" 7 | license = "MIT" 8 | -------------------------------------------------------------------------------- /thread-bound/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | //! Module for tracking the current thread, and wrapping non-`Send` objects in 3 | //! guards that perform runtime thread checks. 4 | 5 | use std::sync::Arc; 6 | use std::fmt::{self, Debug}; 7 | use std::ptr; 8 | use std::mem; 9 | use std::cell::Cell; 10 | 11 | /// A permanent identifier for a single thread, which will not be reused. 12 | #[derive(Clone)] 13 | pub struct ThreadId(Arc<()>); 14 | 15 | impl PartialEq for ThreadId { 16 | fn eq(&self, other: &Self) -> bool { 17 | (&*self.0 as *const ()) == (&*other.0 as *const ()) 18 | } 19 | } 20 | impl Eq for ThreadId {} 21 | 22 | impl Debug for ThreadId { 23 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 24 | write!(f, "thread({:?})", &*self.0 as *const ()) 25 | } 26 | } 27 | 28 | impl ThreadId { 29 | /// Returns true if this `ThreadId` value represents the calling thread. 30 | pub fn is_current(&self) -> bool { 31 | THREAD_NONCE.with(|r| r == self) 32 | } 33 | } 34 | 35 | // consider using https://github.com/rust-lang/rust/pull/29447 after it lands, 36 | // or a u64 atomic where available 37 | // is there a lock-free way to increment a 64-bit counter? 38 | thread_local!(static THREAD_NONCE: ThreadId = ThreadId(Arc::new(()))); 39 | 40 | /// Returns a persistent identifier for the current thread. 41 | pub fn current_thread_id() -> ThreadId { 42 | THREAD_NONCE.with(|r| r.clone()) 43 | } 44 | 45 | struct TBListHead { 46 | // do not move 47 | owner: ThreadId, 48 | head: TBHeader, 49 | destroying: Cell, 50 | } 51 | 52 | /// A container for values which must be accessed within a particular scope in a particular thread. 53 | /// Values may be added using the `bind_value` method, which returns a capability; the capability 54 | /// may freely move between threads, but can only be used in the thread of the binding. A bound 55 | /// value will be destroyed when the capability is destroyed if that happens in the allowed thread; 56 | /// otherwise it will be destroyed when the list is. 57 | pub struct TBList { 58 | list: Arc, 59 | } 60 | 61 | struct TBHeader { 62 | // do not move 63 | next: Cell<*const TBHeader>, 64 | prev: Cell<*const TBHeader>, 65 | free: unsafe fn(*const TBHeader), 66 | } 67 | 68 | struct TBVar { 69 | // do not move 70 | value: T, 71 | header: TBHeader, 72 | } 73 | 74 | /// A handle to a value of type `T` which is owned by a specific thread. Code running on the same 75 | /// thread can freely manipulate the value; attempts to manipulate the value from other threads 76 | /// will panic at runtime. 77 | /// 78 | /// Lifetime is subtle. Since we do not assume `T` can be safely dropped from any thread other 79 | /// than that where it was created, dropping a `ThreadBound` will only immediately drop the 80 | /// wrapped value in the originating thread. Drops occuring on other threads will leave the value 81 | /// in a thread-local list associated with the originating thread, and the value will live until 82 | /// the originating thread exits, at which point it will be destroyed. Conversely, if the 83 | /// originating thread exits while there are `ThreadBound` capabilities alive in the heap, all 84 | /// of the underlying values will be dropped (this causes the capabilities to become dangling 85 | /// pointers, but that is OK as the only thread that could dereference them is exiting). 86 | pub struct ThreadBound { 87 | list: Arc, 88 | var: *mut TBVar, 89 | } 90 | 91 | unsafe impl Send for ThreadBound {} 92 | unsafe impl Sync for ThreadBound {} 93 | 94 | unsafe fn unlink_var(header: *const TBHeader) { 95 | // precondition: the list is being destroyed or the capability has just been 96 | // dropped 97 | // (either way there will be no future attempts to access this header) 98 | // println!("unlink header {:?}", header); 99 | let prev = (*header).prev.get(); 100 | let next = (*header).next.get(); 101 | (*next).prev.set(prev); 102 | (*prev).next.set(next); 103 | } 104 | 105 | // unsafe fn list_dumper(why: &'static str, lh: &TBListHead) { 106 | // let pstart = &lh.head as *const TBHeader; 107 | // let mut p2 = pstart; 108 | // println!("list dump {}", why); 109 | // loop { 110 | // println!("header@{:?}, next={next:?}, prev={prev:?}, free={free:?}", 111 | // p2, 112 | // next = (*p2).next.get(), prev = (*p2).prev.get(), free = 113 | // (*p2).free); 114 | // p2 = (*p2).next.get(); 115 | // if p2 == pstart { break; } 116 | // } 117 | // } 118 | 119 | unsafe fn destroy_var(header: *const TBHeader) { 120 | // println!("destroy header {:?}", header); 121 | unlink_var(header); 122 | ((*header).free)(header); 123 | } 124 | 125 | impl Drop for TBList { 126 | fn drop(&mut self) { 127 | self.list.destroying.set(true); 128 | let headp = &self.list.head as *const TBHeader; 129 | 130 | unsafe { 131 | // list_dumper("A",&*self.list); 132 | while (*headp).next.get() != headp { 133 | destroy_var((*headp).next.get()); 134 | } 135 | } 136 | } 137 | } 138 | 139 | impl Drop for ThreadBound { 140 | fn drop(&mut self) { 141 | if self.list.owner.is_current() && !self.list.destroying.get() { 142 | unsafe { 143 | // list_dumper("B", &*self.list); 144 | destroy_var(&(*self.var).header); 145 | } 146 | } 147 | // otherwise the var leaks and will be cleaned up when the originating thread 148 | // exits. we could provide a scrub() function to call from the originating 149 | // thread, at the cost of extra synchronization. 150 | } 151 | } 152 | 153 | impl TBList { 154 | fn new() -> Self { 155 | unsafe fn unreachable(_head: *const TBHeader) { 156 | panic!("attempt to free TBList header"); 157 | } 158 | let lheader = Arc::new(TBListHead { 159 | owner: current_thread_id(), 160 | destroying: Cell::new(false), 161 | head: TBHeader { 162 | next: Cell::new(ptr::null_mut()), 163 | prev: Cell::new(ptr::null_mut()), 164 | free: unreachable, 165 | }, 166 | }); 167 | let headp = &lheader.head as *const TBHeader; 168 | // println!("insert header {:?}", headp); 169 | unsafe { 170 | (*headp).next.set(headp); 171 | (*headp).prev.set(headp); 172 | // list_dumper("C", &*lheader); 173 | } 174 | TBList { list: lheader } 175 | } 176 | 177 | /// Creates a new scope for value bindings. The lifetime of a scope list is forced to be a 178 | /// dynamic scope so that it will be properly nested with all `with` and `with_mut` borrows. 179 | pub fn scope(f: F) -> R 180 | where F: FnOnce(&mut Self) -> R 181 | { 182 | f(&mut Self::new()) 183 | } 184 | 185 | /// Transfers ownership of a value into a scope, and returns a capability which can be used to 186 | /// access that value but only within the same thread and during the same scope. 187 | pub fn bind(&self, value: T) -> ThreadBound { 188 | unsafe fn free(header: *const TBHeader) { 189 | let offset = &(*(0 as *const TBVar)).header as *const TBHeader as usize; 190 | let varp = ((header as usize) - offset) as *mut TBVar; 191 | // println!("free/box {:?}", varp); 192 | mem::drop(Box::from_raw(varp)); 193 | } 194 | 195 | let new_var: *mut TBVar = Box::into_raw(Box::new(TBVar { 196 | header: TBHeader { 197 | next: Cell::new(ptr::null_mut()), 198 | prev: Cell::new(ptr::null_mut()), 199 | free: free::, 200 | }, 201 | value: value, 202 | })); 203 | 204 | unsafe { 205 | let new_head = &(*new_var).header as *const TBHeader; 206 | let list_head = &self.list.head as *const TBHeader; 207 | 208 | (*new_head).next.set(list_head); 209 | (*new_head).prev.set((*list_head).prev.get()); 210 | (*(*list_head).prev.get()).next.set(new_head); 211 | (*list_head).prev.set(new_head); 212 | // list_dumper("D", &*self.list); 213 | } 214 | 215 | ThreadBound { 216 | var: new_var, 217 | list: self.list.clone(), 218 | } 219 | } 220 | } 221 | 222 | thread_local!(static THREAD_LIST_KEY: TBList = TBList::new()); 223 | 224 | impl ThreadBound { 225 | /// Wraps a value of type `T` in a capability bound to the current thread. This uses a 226 | /// thread-local instance of `TBList` with the lifetime of the calling thread. 227 | pub fn new(inner: T) -> Self { 228 | THREAD_LIST_KEY.with(|tl| tl.bind(inner)) 229 | } 230 | 231 | /// Returns true if this capability can be used without panicking. This will remain true on 232 | /// the same thread as long as the thread does not enter the TLS destruction phase. 233 | pub fn accessible(&self) -> bool { 234 | return self.list.owner.is_current() && !self.list.destroying.get(); 235 | } 236 | 237 | fn check_access(&self) { 238 | if !self.list.owner.is_current() { 239 | panic!("Attempt to access ThreadBound from incorrect thread"); 240 | } 241 | 242 | if self.list.destroying.get() { 243 | panic!("Attempt to access ThreadBound during TLS destruction phase"); 244 | } 245 | } 246 | 247 | /// Consumes this capability to regain ownership of the underlying value. 248 | /// 249 | /// # Panics 250 | /// 251 | /// Panics if the capability is not accessible. 252 | pub fn into_inner(self) -> T { 253 | self.check_access(); 254 | unsafe { 255 | unlink_var(&(*self.var).header as *const TBHeader); 256 | // yes, this is a move, so it invalidates the next/prev 257 | // println!("from_raw {:?}",self.var); 258 | let var_guts: TBVar = *Box::from_raw(self.var); 259 | mem::forget(self); // no double free 260 | var_guts.value 261 | } 262 | } 263 | 264 | /// Temporarily acquires shared access to the guarded value. It would not be safe to return a 265 | /// reference as by the standard `Deref` traits, as the lifetime of the capability could be 266 | /// much longer than the usable life of the referred value. By only exposing borrowing and 267 | /// scoping as functions, we force the lifetimes of values and capabilities to be properly 268 | /// nested with each other in a thread, so a single liveness check at the beginning can 269 | /// suffice. 270 | /// 271 | /// # Panics 272 | /// 273 | /// Panics if the capability is not accessible. 274 | pub fn with(&self, fun: F) -> R 275 | where F: FnOnce(&T) -> R 276 | { 277 | self.check_access(); 278 | fun(unsafe { &(*self.var).value }) 279 | } 280 | 281 | /// Temporarily acquires exclusive access to the guarded value. See safety notes on `with`. 282 | /// 283 | /// # Panics 284 | /// 285 | /// Panics if the capability is not accessible. 286 | pub fn with_mut(&mut self, fun: F) -> R 287 | where F: FnOnce(&mut T) -> R 288 | { 289 | self.check_access(); 290 | fun(unsafe { &mut (*self.var).value }) 291 | } 292 | } 293 | 294 | #[cfg(test)] 295 | mod tests { 296 | use super::*; 297 | use std::thread; 298 | use std::mem; 299 | use std::sync::{Arc, Mutex}; 300 | 301 | #[test] 302 | fn same_thread_id() { 303 | let id1 = current_thread_id(); 304 | let id2 = current_thread_id(); 305 | 306 | assert_eq!(id1, id2); 307 | assert!(id1.is_current()); 308 | } 309 | 310 | #[test] 311 | fn thread_id_formatting() { 312 | let strg = format!("{:?}", current_thread_id()); 313 | assert!(strg.starts_with("thread(")); 314 | } 315 | 316 | #[test] 317 | fn different_thread_id() { 318 | let id1 = current_thread_id(); 319 | let id2 = thread::spawn(|| current_thread_id()).join().unwrap(); 320 | 321 | assert!(id1 != id2); 322 | assert!(!id2.is_current()); 323 | } 324 | 325 | #[test] 326 | fn round_tripping() { 327 | let y = 42; 328 | let mut cap = ThreadBound::new(y); 329 | 330 | assert!(cap.accessible()); 331 | 332 | cap.with(|r1| assert_eq!(*r1, 42)); 333 | cap.with_mut(|r2| assert_eq!(*r2, 42)); 334 | let r3: i32 = cap.into_inner(); 335 | assert_eq!(r3, 42); 336 | } 337 | 338 | #[test] 339 | fn wrong_thread_throws() { 340 | let mut cap = ThreadBound::new(42); 341 | let joinh = thread::spawn(move || cap.with_mut(|r| *r = 55)); 342 | let res: Box<&'static str> = joinh.join().err().unwrap().downcast().unwrap(); 343 | assert_eq!(*res, "Attempt to access ThreadBound from incorrect thread") 344 | } 345 | 346 | #[test] 347 | fn wrong_thread_inaccessible() { 348 | let cap = ThreadBound::new(42); 349 | assert!(!thread::spawn(move || cap.accessible()).join().unwrap()); 350 | } 351 | 352 | struct Trap(Arc>); 353 | impl Drop for Trap { 354 | fn drop(&mut self) { 355 | (*self.0.lock().unwrap()) = true; 356 | } 357 | } 358 | 359 | #[test] 360 | fn inaccessible_after_teardown() { 361 | let cap = TBList::scope(|list| list.bind(42)); 362 | assert!(!cap.accessible()); 363 | 364 | let joinh = thread::spawn(|| { 365 | let mut cap2 = TBList::scope(|list| list.bind(42)); 366 | cap2.with_mut(|r| *r = 55); 367 | }); 368 | let error: Box<&'static str> = joinh.join().err().unwrap().downcast().unwrap(); 369 | 370 | assert_eq!(*error, 371 | "Attempt to access ThreadBound during TLS destruction phase"); 372 | } 373 | 374 | #[test] 375 | fn sync_drop() { 376 | let was_dropped = Arc::new(Mutex::new(false)); 377 | let cap = ThreadBound::new(Trap(was_dropped.clone())); 378 | mem::drop(cap); 379 | assert!(*was_dropped.lock().unwrap()); 380 | } 381 | 382 | #[test] 383 | fn async_drop() { 384 | let was_dropped = Arc::new(Mutex::new(false)); 385 | let was_dropped_2 = was_dropped.clone(); 386 | let early_dropped = Arc::new(Mutex::new(false)); 387 | let early_dropped_2 = early_dropped.clone(); 388 | let thr = thread::spawn(move || { 389 | let cap = ThreadBound::new(Trap(was_dropped_2.clone())); 390 | thread::spawn(move || mem::drop(cap)).join().unwrap(); 391 | (*early_dropped_2.lock().unwrap()) = *was_dropped_2.lock().unwrap(); 392 | }); 393 | thr.join().unwrap(); 394 | assert!(!*early_dropped.lock().unwrap()); 395 | assert!(*was_dropped.lock().unwrap()); 396 | } 397 | } 398 | --------------------------------------------------------------------------------