Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move C API to submodule #845

Merged
merged 8 commits into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/HDF5.jl
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,6 @@ function Base.cconvert(::Type{Ptr{Cvoid}}, v::VLen)
return h
end

include("error.jl")
include("show.jl")

# Blosc compression:
Expand Down
23 changes: 2 additions & 21 deletions src/api/api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,9 @@ else
"and restart Julia.")
end

# stub: methods defined in error.jl
macro h5error(msg)
# Check if the is actually any errors on the stack. This is necessary as there are a
# small number of functions which return `0` in case of an error, but `0` is also a
# valid return value, e.g. `h5t_get_member_offset`

# This needs to be a macro as we need to call `h5e_get_current_stack()` _before_
# evaluating the message expression, as some message expressions can call API
# functions, which would clear the error stack.
quote
err_id = h5e_get_current_stack()
if h5e_get_num(err_id) > 0
throw(HDF5.H5Error($(esc(msg)), err_id))
else
h5e_close_stack(err_id)
end
end
end

# Core API ccall wrappers
include("types.jl")
include("functions.jl")
include("error.jl")
include("functions.jl") # core API ccall wrappers
include("helpers.jl")

end
42 changes: 30 additions & 12 deletions src/error.jl → src/api/error.jl
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@

"""
H5Error
H5Error

An error thrown by libhdf5.
"""
mutable struct H5Error <: Exception
msg::String
id::API.hid_t
id::hid_t
end

macro h5error(msg)
# Check if the is actually any errors on the stack. This is necessary as there are a
# small number of functions which return `0` in case of an error, but `0` is also a
# valid return value, e.g. `h5t_get_member_offset`

# This needs to be a macro as we need to call `h5e_get_current_stack()` _before_
# evaluating the message expression, as some message expressions can call API
# functions, which would clear the error stack.
quote
err_id = h5e_get_current_stack()
if h5e_get_num(err_id) > 0
throw(H5Error($(esc(msg)), err_id))
else
h5e_close_stack(err_id)
end
end
end

Base.cconvert(::Type{API.hid_t}, err::H5Error) = err
Base.unsafe_convert(::Type{API.hid_t}, err::H5Error) = err.id
Base.cconvert(::Type{hid_t}, err::H5Error) = err
Base.unsafe_convert(::Type{hid_t}, err::H5Error) = err.id

function Base.close(err::H5Error)
if err.id != -1 && isvalid(err)
API.h5e_close_stack(err)
h5e_close_stack(err)
err.id = -1
end
return nothing
end
Base.isvalid(err::H5Error) = err.id != -1 && API.h5i_is_valid(err)
Base.isvalid(err::H5Error) = err.id != -1 && h5i_is_valid(err)

Base.length(err::H5Error) = API.h5e_get_num(err)
Base.length(err::H5Error) = h5e_get_num(err)
Base.isempty(err::H5Error) = length(err) == 0

function H5Error(msg::AbstractString)
id = API.h5e_get_current_stack()
id = h5e_get_current_stack()
err = H5Error(msg, id)
finalizer(close, err)
return err
Expand All @@ -35,9 +53,9 @@ const SHORT_ERROR = Ref(true)

function Base.showerror(io::IO, err::H5Error)
n_total = length(err)
print(io, "H5Error: ", err.msg)
print(io, "$(typeof(err)): ", err.msg)
Copy link
Member

@musm musm Jun 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used typeof here so that the full module path is printed:
image

I think this is a good idea in case we decide to use the same exception error name in the main module.

print(io, "\nlibhdf5 Stacktrace:")
API.h5e_walk(err, H5E_WALK_UPWARD) do n, errptr
h5e_walk(err, H5E_WALK_UPWARD) do n, errptr
n += 1
if SHORT_ERROR[] && 1 < n < n_total
return nothing
Expand All @@ -48,8 +66,8 @@ function Base.showerror(io::IO, err::H5Error)
printstyled(io, unsafe_string(errval.func_name); bold=true)
print(io, ": ")
end
major = API.h5e_get_msg(errval.maj_num)[2]
minor = API.h5e_get_msg(errval.min_num)[2]
major = h5e_get_msg(errval.maj_num)[2]
minor = h5e_get_msg(errval.min_num)[2]
print(io, major, "/", minor)
if errval.desc != C_NULL
printstyled(io, "\n", " "^(4 + ndigits(n_total)), unsafe_string(errval.desc), color=:light_black)
Expand Down
6 changes: 3 additions & 3 deletions test/plain.jl
Original file line number Diff line number Diff line change
Expand Up @@ -433,10 +433,10 @@ end # testset "Test h5d_fill
gatherf_ptr = @cfunction(gatherf, HDF5.API.herr_t, (Ptr{Nothing}, Csize_t, Ptr{Nothing}))
@test HDF5.API.h5d_gather(dataspace(d), src_buf, datatype(Int), sizeof(dst_buf)÷2, dst_buf, gatherf_ptr, C_NULL) |> isnothing
gatherf_bad_ptr = @cfunction(gatherf_bad, HDF5.API.herr_t, (Ptr{Nothing}, Csize_t, Ptr{Nothing}))
@test_throws HDF5.H5Error HDF5.API.h5d_gather(dataspace(d), src_buf, datatype(Int), sizeof(dst_buf)÷2, dst_buf, gatherf_bad_ptr, C_NULL)
@test_throws HDF5.API.H5Error HDF5.API.h5d_gather(dataspace(d), src_buf, datatype(Int), sizeof(dst_buf)÷2, dst_buf, gatherf_bad_ptr, C_NULL)
gatherf_data_ptr = @cfunction(gatherf_data, HDF5.API.herr_t, (Ptr{Nothing}, Csize_t, Ref{Int}))
@test HDF5.API.h5d_gather(dataspace(d), src_buf, datatype(Int), sizeof(dst_buf)÷2, dst_buf, gatherf_data_ptr, Ref(9)) |> isnothing
@test_throws HDF5.H5Error HDF5.API.h5d_gather(dataspace(d), src_buf, datatype(Int), sizeof(dst_buf)÷2, dst_buf, gatherf_data_ptr, 10)
@test_throws HDF5.API.H5Error HDF5.API.h5d_gather(dataspace(d), src_buf, datatype(Int), sizeof(dst_buf)÷2, dst_buf, gatherf_data_ptr, 10)
end
rm(fn)
end
Expand All @@ -451,7 +451,7 @@ end
scatterf_ptr = @cfunction(scatterf, HDF5.API.herr_t, (Ptr{Ptr{Nothing}}, Ptr{Csize_t}, Ptr{Nothing}))
@test HDF5.API.h5d_scatter(scatterf_ptr, C_NULL, datatype(Int), dataspace(d), dst_buf) |> isnothing
scatterf_bad_ptr = @cfunction(scatterf_bad, HDF5.API.herr_t, (Ptr{Ptr{Nothing}}, Ptr{Csize_t}, Ptr{Nothing}))
@test_throws HDF5.H5Error HDF5.API.h5d_scatter(scatterf_bad_ptr, C_NULL, datatype(Int), dataspace(d), dst_buf)
@test_throws HDF5.API.H5Error HDF5.API.h5d_scatter(scatterf_bad_ptr, C_NULL, datatype(Int), dataspace(d), dst_buf)
scatterf_data_ptr = @cfunction(scatterf_data, HDF5.API.herr_t, (Ptr{Ptr{Int}}, Ptr{Csize_t}, Ref{Int}))
@test HDF5.API.h5d_scatter(scatterf_data_ptr, Ref(9), datatype(Int), dataspace(d), dst_buf) |> isnothing
end
Expand Down
2 changes: 1 addition & 1 deletion test/properties.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ h5open(fn, "w";
@test fapl[:alignment] == (0, sizeof(Int))
# value is H5FD_SEC2, but "constant" is runtime value not loadable by _read_const()
@test HDF5.API.h5i_get_type(fapl[:driver]) == HDF5.API.H5I_VFL
@test_throws HDF5.H5Error fapl[:driver_info]
@test_throws HDF5.API.H5Error fapl[:driver_info]
@test fapl[:fclose_degree] == HDF5.API.H5F_CLOSE_STRONG
@test fapl[:libver_bounds] == (HDF5.API.H5F_LIBVER_EARLIEST, HDF5.API.H5F_LIBVER_LATEST)

Expand Down