mirror of
git://git.proxmox.com/git/perlmod.git
synced 2025-01-03 09:17:39 +03:00
add ability to set the errno value
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
2aa0c70d0d
commit
56bb74b196
@ -129,6 +129,7 @@ pub struct FunctionAttrs {
|
||||
pub cv_variable: Option<Ident>,
|
||||
pub prototype: Option<String>,
|
||||
pub serialize_error: bool,
|
||||
pub errno: bool,
|
||||
}
|
||||
|
||||
impl TryFrom<AttributeArgs> for FunctionAttrs {
|
||||
@ -160,6 +161,8 @@ impl TryFrom<AttributeArgs> for FunctionAttrs {
|
||||
attrs.raw_return = true;
|
||||
} else if path.is_ident("serialize_error") {
|
||||
attrs.serialize_error = true;
|
||||
} else if path.is_ident("errno") {
|
||||
attrs.errno = true;
|
||||
} else {
|
||||
error!(path => "unknown attribute");
|
||||
}
|
||||
|
@ -368,6 +368,12 @@ fn handle_return_kind(
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
let copy_errno = if attr.errno {
|
||||
quote! { ::perlmod::error::copy_errno_to_libc(); }
|
||||
} else {
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
let pthx = crate::pthx_param();
|
||||
match ret.value {
|
||||
ReturnValue::None => {
|
||||
@ -398,7 +404,9 @@ fn handle_return_kind(
|
||||
#[doc(hidden)]
|
||||
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
|
||||
unsafe {
|
||||
match #impl_xs_name(#cv_arg_passed) {
|
||||
let res = #impl_xs_name(#cv_arg_passed);
|
||||
#copy_errno
|
||||
match res {
|
||||
Ok(()) => (),
|
||||
Err(sv) => ::perlmod::ffi::croak(sv),
|
||||
}
|
||||
@ -441,7 +449,9 @@ fn handle_return_kind(
|
||||
#[doc(hidden)]
|
||||
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
|
||||
unsafe {
|
||||
match #impl_xs_name(#cv_arg_passed) {
|
||||
let res = #impl_xs_name(#cv_arg_passed);
|
||||
#copy_errno
|
||||
match res {
|
||||
Ok(sv) => ::perlmod::ffi::stack_push_raw(sv),
|
||||
Err(sv) => ::perlmod::ffi::croak(sv),
|
||||
}
|
||||
@ -523,7 +533,9 @@ fn handle_return_kind(
|
||||
#[doc(hidden)]
|
||||
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
|
||||
unsafe {
|
||||
match #impl_xs_name(#cv_arg_passed) {
|
||||
let res = #impl_xs_name(#cv_arg_passed);
|
||||
#copy_errno
|
||||
match res {
|
||||
Ok(sv) => { #push },
|
||||
Err(sv) => ::perlmod::ffi::croak(sv),
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ mod export {
|
||||
b: String,
|
||||
}
|
||||
|
||||
#[export(serialize_error)]
|
||||
#[export(serialize_error, errno)]
|
||||
fn test_deserialized_error(fail: bool) -> Result<&'static str, MyError> {
|
||||
if fail {
|
||||
Err(MyError {
|
||||
@ -100,6 +100,7 @@ mod export {
|
||||
b: "second".to_string(),
|
||||
})
|
||||
} else {
|
||||
::perlmod::error::set_errno(77);
|
||||
Ok("worked")
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
//! Error types.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt;
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Error returned by `TryFrom` implementations between `Scalar`, `Array` and `Hash`.
|
||||
#[derive(Debug)]
|
||||
@ -84,3 +86,30 @@ impl fmt::Display for MagicError {
|
||||
}
|
||||
|
||||
impl std::error::Error for MagicError {}
|
||||
|
||||
thread_local! {
|
||||
static ERRNO: Cell<c_int> = Cell::new(0);
|
||||
}
|
||||
|
||||
/// Set the perlmod-specific `errno` value. This is *not* libc's `errno`, but a separate storage
|
||||
/// location not touched by other C or perl functions. An `#[export(errno)]` function will copy
|
||||
/// this value to libc's errno location at right before returning into the perl stack (*after* all
|
||||
/// side effects such as destructors have already finished).
|
||||
pub fn set_errno(value: c_int) {
|
||||
ERRNO.with(|v| v.set(value))
|
||||
}
|
||||
|
||||
/// *Not* `libc`'s `errno`, this retrieves a value previously set with [`set_errno`], see its
|
||||
/// description for details.
|
||||
pub fn get_errno() -> c_int {
|
||||
ERRNO.with(|v| v.get())
|
||||
}
|
||||
|
||||
/// This is part of the proc-macro API and is of little use to users of this crate directly.
|
||||
/// When manually implementing "xsubs" this can be used before returning as a shortcut to copying
|
||||
/// the perlmod errno value to libc.
|
||||
pub unsafe fn copy_errno_to_libc() {
|
||||
unsafe {
|
||||
libc::__errno_location().write(get_errno());
|
||||
}
|
||||
}
|
||||
|
1
test.pl
1
test.pl
@ -122,6 +122,7 @@ my $sub = RSPM::Foo142::test_substr_return($orig);
|
||||
print("[$orig] [$sub]\n");
|
||||
|
||||
my $ok = RSPM::Foo142::test_deserialized_error(0);
|
||||
die "test_deserialized_error failed to set errno value\n" if $! != 77;
|
||||
die "test_deserialized_error failed to return a value\n" if $ok ne 'worked';
|
||||
$ok = eval { RSPM::Foo142::test_deserialized_error(1) };
|
||||
die "test_deserialized_error error case returned a value\n" if defined $ok;
|
||||
|
Loading…
Reference in New Issue
Block a user