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 cv_variable: Option<Ident>,
|
||||||
pub prototype: Option<String>,
|
pub prototype: Option<String>,
|
||||||
pub serialize_error: bool,
|
pub serialize_error: bool,
|
||||||
|
pub errno: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<AttributeArgs> for FunctionAttrs {
|
impl TryFrom<AttributeArgs> for FunctionAttrs {
|
||||||
@ -160,6 +161,8 @@ impl TryFrom<AttributeArgs> for FunctionAttrs {
|
|||||||
attrs.raw_return = true;
|
attrs.raw_return = true;
|
||||||
} else if path.is_ident("serialize_error") {
|
} else if path.is_ident("serialize_error") {
|
||||||
attrs.serialize_error = true;
|
attrs.serialize_error = true;
|
||||||
|
} else if path.is_ident("errno") {
|
||||||
|
attrs.errno = true;
|
||||||
} else {
|
} else {
|
||||||
error!(path => "unknown attribute");
|
error!(path => "unknown attribute");
|
||||||
}
|
}
|
||||||
|
@ -368,6 +368,12 @@ fn handle_return_kind(
|
|||||||
TokenStream::new()
|
TokenStream::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let copy_errno = if attr.errno {
|
||||||
|
quote! { ::perlmod::error::copy_errno_to_libc(); }
|
||||||
|
} else {
|
||||||
|
TokenStream::new()
|
||||||
|
};
|
||||||
|
|
||||||
let pthx = crate::pthx_param();
|
let pthx = crate::pthx_param();
|
||||||
match ret.value {
|
match ret.value {
|
||||||
ReturnValue::None => {
|
ReturnValue::None => {
|
||||||
@ -398,7 +404,9 @@ fn handle_return_kind(
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
|
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
|
||||||
unsafe {
|
unsafe {
|
||||||
match #impl_xs_name(#cv_arg_passed) {
|
let res = #impl_xs_name(#cv_arg_passed);
|
||||||
|
#copy_errno
|
||||||
|
match res {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(sv) => ::perlmod::ffi::croak(sv),
|
Err(sv) => ::perlmod::ffi::croak(sv),
|
||||||
}
|
}
|
||||||
@ -441,7 +449,9 @@ fn handle_return_kind(
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
|
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
|
||||||
unsafe {
|
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),
|
Ok(sv) => ::perlmod::ffi::stack_push_raw(sv),
|
||||||
Err(sv) => ::perlmod::ffi::croak(sv),
|
Err(sv) => ::perlmod::ffi::croak(sv),
|
||||||
}
|
}
|
||||||
@ -523,7 +533,9 @@ fn handle_return_kind(
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
|
#vis extern "C" fn #xs_name(#pthx #cv_arg_name: *mut ::perlmod::ffi::CV) {
|
||||||
unsafe {
|
unsafe {
|
||||||
match #impl_xs_name(#cv_arg_passed) {
|
let res = #impl_xs_name(#cv_arg_passed);
|
||||||
|
#copy_errno
|
||||||
|
match res {
|
||||||
Ok(sv) => { #push },
|
Ok(sv) => { #push },
|
||||||
Err(sv) => ::perlmod::ffi::croak(sv),
|
Err(sv) => ::perlmod::ffi::croak(sv),
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ mod export {
|
|||||||
b: String,
|
b: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[export(serialize_error)]
|
#[export(serialize_error, errno)]
|
||||||
fn test_deserialized_error(fail: bool) -> Result<&'static str, MyError> {
|
fn test_deserialized_error(fail: bool) -> Result<&'static str, MyError> {
|
||||||
if fail {
|
if fail {
|
||||||
Err(MyError {
|
Err(MyError {
|
||||||
@ -100,6 +100,7 @@ mod export {
|
|||||||
b: "second".to_string(),
|
b: "second".to_string(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
::perlmod::error::set_errno(77);
|
||||||
Ok("worked")
|
Ok("worked")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
//! Error types.
|
//! Error types.
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
/// Error returned by `TryFrom` implementations between `Scalar`, `Array` and `Hash`.
|
/// Error returned by `TryFrom` implementations between `Scalar`, `Array` and `Hash`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -84,3 +86,30 @@ impl fmt::Display for MagicError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error 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");
|
print("[$orig] [$sub]\n");
|
||||||
|
|
||||||
my $ok = RSPM::Foo142::test_deserialized_error(0);
|
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';
|
die "test_deserialized_error failed to return a value\n" if $ok ne 'worked';
|
||||||
$ok = eval { RSPM::Foo142::test_deserialized_error(1) };
|
$ok = eval { RSPM::Foo142::test_deserialized_error(1) };
|
||||||
die "test_deserialized_error error case returned a value\n" if defined $ok;
|
die "test_deserialized_error error case returned a value\n" if defined $ok;
|
||||||
|
Loading…
Reference in New Issue
Block a user