From 79a3ad2b950009f560641cea359d7deb6f7a61ac Mon Sep 17 00:00:00 2001 From: snek Date: Thu, 24 Oct 2024 09:13:54 +0200 Subject: feat: support node-api in denort (#26389) exposes node-api symbols in denort so that `deno compile` can run native addons. --- ext/napi/uv.rs | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 ext/napi/uv.rs (limited to 'ext/napi/uv.rs') diff --git a/ext/napi/uv.rs b/ext/napi/uv.rs new file mode 100644 index 000000000..6f728a92b --- /dev/null +++ b/ext/napi/uv.rs @@ -0,0 +1,231 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::*; +use deno_core::parking_lot::Mutex; +use std::mem::MaybeUninit; +use std::ptr::addr_of_mut; + +#[allow(clippy::print_stderr)] +fn assert_ok(res: c_int) -> c_int { + if res != 0 { + eprintln!("bad result in uv polyfill: {res}"); + // don't panic because that might unwind into + // c/c++ + std::process::abort(); + } + res +} + +use js_native_api::napi_create_string_utf8; +use node_api::napi_create_async_work; +use node_api::napi_delete_async_work; +use node_api::napi_queue_async_work; +use std::ffi::c_int; + +const UV_MUTEX_SIZE: usize = { + #[cfg(unix)] + { + std::mem::size_of::() + } + #[cfg(windows)] + { + std::mem::size_of::( + ) + } +}; + +#[repr(C)] +struct uv_mutex_t { + mutex: Mutex<()>, + _padding: [MaybeUninit; const { + (UV_MUTEX_SIZE - size_of::>()) / size_of::() + }], +} + +#[no_mangle] +unsafe extern "C" fn uv_mutex_init(lock: *mut uv_mutex_t) -> c_int { + unsafe { + addr_of_mut!((*lock).mutex).write(Mutex::new(())); + 0 + } +} + +#[no_mangle] +unsafe extern "C" fn uv_mutex_lock(lock: *mut uv_mutex_t) { + unsafe { + let guard = (*lock).mutex.lock(); + // forget the guard so it doesn't unlock when it goes out of scope. + // we're going to unlock it manually + std::mem::forget(guard); + } +} + +#[no_mangle] +unsafe extern "C" fn uv_mutex_unlock(lock: *mut uv_mutex_t) { + unsafe { + (*lock).mutex.force_unlock(); + } +} + +#[no_mangle] +unsafe extern "C" fn uv_mutex_destroy(_lock: *mut uv_mutex_t) { + // no cleanup required +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +#[allow(dead_code)] +enum uv_handle_type { + UV_UNKNOWN_HANDLE = 0, + UV_ASYNC, + UV_CHECK, + UV_FS_EVENT, + UV_FS_POLL, + UV_HANDLE, + UV_IDLE, + UV_NAMED_PIPE, + UV_POLL, + UV_PREPARE, + UV_PROCESS, + UV_STREAM, + UV_TCP, + UV_TIMER, + UV_TTY, + UV_UDP, + UV_SIGNAL, + UV_FILE, + UV_HANDLE_TYPE_MAX, +} + +const UV_HANDLE_SIZE: usize = 96; + +#[repr(C)] +struct uv_handle_t { + // public members + pub data: *mut c_void, + pub r#loop: *mut uv_loop_t, + pub r#type: uv_handle_type, + + _padding: [MaybeUninit; const { + (UV_HANDLE_SIZE + - size_of::<*mut c_void>() + - size_of::<*mut uv_loop_t>() + - size_of::()) + / size_of::() + }], +} + +#[cfg(unix)] +const UV_ASYNC_SIZE: usize = 128; + +#[cfg(windows)] +const UV_ASYNC_SIZE: usize = 224; + +#[repr(C)] +struct uv_async_t { + // public members + pub data: *mut c_void, + pub r#loop: *mut uv_loop_t, + pub r#type: uv_handle_type, + // private + async_cb: uv_async_cb, + work: napi_async_work, + _padding: [MaybeUninit; const { + (UV_ASYNC_SIZE + - size_of::<*mut c_void>() + - size_of::<*mut uv_loop_t>() + - size_of::() + - size_of::() + - size_of::()) + / size_of::() + }], +} + +type uv_loop_t = Env; +type uv_async_cb = extern "C" fn(handle: *mut uv_async_t); +#[no_mangle] +unsafe extern "C" fn uv_async_init( + r#loop: *mut uv_loop_t, + // probably uninitialized + r#async: *mut uv_async_t, + async_cb: uv_async_cb, +) -> c_int { + unsafe { + addr_of_mut!((*r#async).r#loop).write(r#loop); + addr_of_mut!((*r#async).r#type).write(uv_handle_type::UV_ASYNC); + addr_of_mut!((*r#async).async_cb).write(async_cb); + + let mut resource_name: MaybeUninit = MaybeUninit::uninit(); + assert_ok(napi_create_string_utf8( + r#loop, + c"uv_async".as_ptr(), + usize::MAX, + resource_name.as_mut_ptr(), + )); + let resource_name = resource_name.assume_init(); + + let res = napi_create_async_work( + r#loop, + None::>.into(), + resource_name, + Some(async_exec_wrap), + None, + r#async.cast(), + addr_of_mut!((*r#async).work), + ); + -res + } +} + +#[no_mangle] +unsafe extern "C" fn uv_async_send(handle: *mut uv_async_t) -> c_int { + unsafe { -napi_queue_async_work((*handle).r#loop, (*handle).work) } +} + +type uv_close_cb = unsafe extern "C" fn(*mut uv_handle_t); + +#[no_mangle] +unsafe extern "C" fn uv_close(handle: *mut uv_handle_t, close: uv_close_cb) { + unsafe { + if handle.is_null() { + close(handle); + return; + } + if let uv_handle_type::UV_ASYNC = (*handle).r#type { + let handle: *mut uv_async_t = handle.cast(); + napi_delete_async_work((*handle).r#loop, (*handle).work); + } + close(handle); + } +} + +unsafe extern "C" fn async_exec_wrap(_env: napi_env, data: *mut c_void) { + let data: *mut uv_async_t = data.cast(); + unsafe { + ((*data).async_cb)(data); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sizes() { + assert_eq!( + std::mem::size_of::(), + UV_MUTEX_SIZE + ); + assert_eq!( + std::mem::size_of::(), + UV_HANDLE_SIZE + ); + assert_eq!( + std::mem::size_of::(), + UV_ASYNC_SIZE + ); + assert_eq!(std::mem::size_of::(), UV_MUTEX_SIZE); + assert_eq!(std::mem::size_of::(), UV_HANDLE_SIZE); + assert_eq!(std::mem::size_of::(), UV_ASYNC_SIZE); + } +} -- cgit v1.2.3 From 4e899d48cffa95617266dd8f9aef54603a87ad82 Mon Sep 17 00:00:00 2001 From: snek Date: Thu, 14 Nov 2024 13:16:28 +0100 Subject: fix: otel resiliency (#26857) Improving the breadth of collected data, and ensuring that the collected data is more likely to be successfully reported. - Use `log` crate in more places - Hook up `log` crate to otel - Switch to process-wide otel processors - Handle places that use `process::exit` Also adds a more robust testing framework, with a deterministic tracing setting. Refs: https://github.com/denoland/deno/issues/26852 --- ext/napi/uv.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ext/napi/uv.rs') diff --git a/ext/napi/uv.rs b/ext/napi/uv.rs index 6f728a92b..ea6b53966 100644 --- a/ext/napi/uv.rs +++ b/ext/napi/uv.rs @@ -5,10 +5,9 @@ use deno_core::parking_lot::Mutex; use std::mem::MaybeUninit; use std::ptr::addr_of_mut; -#[allow(clippy::print_stderr)] fn assert_ok(res: c_int) -> c_int { if res != 0 { - eprintln!("bad result in uv polyfill: {res}"); + log::error!("bad result in uv polyfill: {res}"); // don't panic because that might unwind into // c/c++ std::process::abort(); -- cgit v1.2.3