Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
16 changes: 11 additions & 5 deletions src/FFTW.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ end

if VERSION >= v"1.11.0"
# This can be be deleted once FFTW_jll is upgraded to the real lazy jll code, to get the real benefits of this mess
mutable struct FakeLazyLibrary
mutable struct FakeLazyLibrary{T}
reallibrary::Symbol
on_load_callback
on_load_callback::T
@atomic h::Ptr{Cvoid}
end
import Libdl: LazyLibrary, dlopen
function dlopen(lib::FakeLazyLibrary)
function dlopen(lib::FakeLazyLibrary{T}) where T
h = @atomic :monotonic lib.h
h != C_NULL && return h
@lock fftwlock begin
h = @atomic :monotonic lib.h
h != C_NULL && return h
h = dlopen(getglobal(FFTW, lib.reallibrary))
h = dlopen(getglobal(FFTW, lib.reallibrary)::String)
lib.on_load_callback()
@atomic :release lib.h = h
end
Expand All @@ -60,7 +60,13 @@ end
const libfftw3 = FakeLazyLibrary(:libfftw3_no_init, fftw_init_check, C_NULL)
const libfftw3f = FakeLazyLibrary(:libfftw3f_no_init, fftw_init_check, C_NULL)

else
if VERSION >= v"1.12.0"
function __init__()
dlopen(libfftw3) # Ensure that dlopen(::FakeLazyLibrary) is built by JuliaC
end
end

else # !(VERSION >= v"1.11.0")
@static if fftw_provider == "fftw"
import FFTW_jll: libfftw3_path as libfftw3_no_init,
libfftw3f_path as libfftw3f_no_init,
Expand Down
27 changes: 19 additions & 8 deletions src/fft.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import Base: show, *, convert, unsafe_convert, size, strides, ndims, pointer
import LinearAlgebra: mul!
import Libdl: dlopen, dlsym

"""
r2r(A, kind [, dims])
Expand Down Expand Up @@ -320,14 +321,24 @@ unsafe_convert(::Type{PlanPtr}, p::FFTWPlan) = p.plan
# pushing the plan to be destroyed to the deferred_destroy_plans (which itself is protected by a lock).
# This is accomplished by the maybe_destroy_plan function, which is used as the plan finalizer.

struct FFTWPlanDestructor
ptr::PlanPtr
fptr::Ptr{Cvoid}
end

FFTWPlanDestructor(plan::FFTWPlan{<:fftwSingle}) =
FFTWPlanDestructor(plan.plan, dlsym(dlopen(libfftw3f), :fftwf_destroy_plan))
FFTWPlanDestructor(plan::FFTWPlan{<:fftwDouble}) =
FFTWPlanDestructor(plan.plan, dlsym(dlopen(libfftw3), :fftw_destroy_plan))

# these functions should only be called while the fftwlock is held
unsafe_destroy_plan(@nospecialize(plan::FFTWPlan{<:fftwDouble})) =
ccall((:fftw_destroy_plan,libfftw3), Cvoid, (PlanPtr,), plan)
unsafe_destroy_plan(@nospecialize(plan::FFTWPlan{<:fftwSingle})) =
ccall((:fftwf_destroy_plan,libfftw3f), Cvoid, (PlanPtr,), plan)
unsafe_destroy_plan(plan::FFTWPlan) = unsafe_destroy_plan(FFTWPlanDestructor(plan))
function unsafe_destroy_plan(destructor::FFTWPlanDestructor)
ccall(destructor.fptr, Cvoid, (PlanPtr, ), destructor.ptr)
end

const deferred_destroy_lock = ReentrantLock() # lock protecting the deferred_destroy_plans list
const deferred_destroy_plans = FFTWPlan[]
const deferred_destroy_plans = FFTWPlanDestructor[]

function destroy_deferred()
lock(deferred_destroy_lock)
Expand Down Expand Up @@ -375,7 +386,7 @@ function maybe_destroy_plan(plan::FFTWPlan)
unlock(fftwlock)
end
else
push!(deferred_destroy_plans, plan)
push!(deferred_destroy_plans, FFTWPlanDestructor(plan))
end
finally
unlock(deferred_destroy_lock)
Expand Down Expand Up @@ -495,11 +506,11 @@ function assert_applicable(p::FFTWPlan{T,K,inplace}, X::StridedArray{T}, Y::Stri
elseif alignment_of(Y) != p.oalign && p.flags & UNALIGNED == 0
throw(ArgumentError("FFTW plan applied to output with wrong memory alignment"))
elseif inplace != (pointer(X) == pointer(Y))
throw(ArgumentError(string("FFTW ",
throw(ArgumentError(join(["FFTW ",
inplace ? "in-place" : "out-of-place",
" plan applied to ",
inplace ? "out-of-place" : "in-place",
" data")))
" data"])))
end
end

Expand Down
16 changes: 14 additions & 2 deletions src/providers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,20 @@ end
# callback function that FFTW uses to launch `num` parallel
# tasks (FFTW/fftw3#175):
function spawnloop(f::Ptr{Cvoid}, fdata::Ptr{Cvoid}, elsize::Csize_t, num::Cint, callback_data::Ptr{Cvoid})
@sync for i = 0:num-1
Threads.@spawn ccall(f, Ptr{Cvoid}, (Ptr{Cvoid},), fdata + elsize*i)
# Wrap the for-loop in a simplified @sync, achieving type stability by not depending on a Channel{Any}.
# This is necessary for JuliaC to compile. The result runs as long as fftw only uses on thread.
# If FFTW.set_num_threads is used to activate more threads, there will still be a runtime error due to @spawn,
# which is limited by https://github.com/JuliaLang/julia/issues/58818 anyway.
tasks = Channel{Task}(Inf)
try
for i = 0:num-1
put!(tasks, Threads.@spawn ccall(f, Ptr{Cvoid}, (Ptr{Cvoid},), fdata + elsize*i))
end
while isready(tasks)
wait(take!(tasks))
end
finally
close(tasks)
end
end

Expand Down
Loading