@@ -89,6 +89,27 @@ alignment_of(A::FakeArray) = Int32(0)
8989
9090# # Julia wrappers around FFTW functions
9191
92+ # _init_() must be called before any FFTW planning routine.
93+ # -- Once FFTW is split into its own module, this can be called
94+ # in the module __init__(), but for now we must call it lazily
95+ # in every routine that might initialize the FFTW planner.
96+ # -- This initializes FFTW's threads support (defaulting to 1 thread).
97+ # If this isn't called before the FFTW planner is created, then
98+ # FFTW's threads algorithms won't be registered or used at all.
99+ # (Previously, we called fftw_cleanup, but this invalidated existing
100+ # plans, causing issue #19892.)
101+ const threads_initialized = Ref (false )
102+ function _init_ ()
103+ if ! threads_initialized[]
104+ stat = ccall ((:fftw_init_threads ,libfftw), Int32, ())
105+ statf = ccall ((:fftwf_init_threads ,libfftwf), Int32, ())
106+ if stat == 0 || statf == 0
107+ error (" could not initialize FFTW threads" )
108+ end
109+ threads_initialized[] = true
110+ end
111+ end
112+
92113# Wisdom
93114
94115# Import and export wisdom to/from a single file for all precisions,
@@ -101,6 +122,7 @@ alignment_of(A::FakeArray) = Int32(0)
101122# FFTW's api/import-wisdom-from-file.c file].
102123
103124function export_wisdom (fname:: AbstractString )
125+ _init_ ()
104126 f = ccall (:fopen , Ptr{Void}, (Cstring,Cstring), fname, :w )
105127 systemerror (" could not open wisdom file $fname for writing" , f == C_NULL )
106128 ccall ((:fftw_export_wisdom_to_file ,libfftw), Void, (Ptr{Void},), f)
@@ -110,6 +132,7 @@ function export_wisdom(fname::AbstractString)
110132end
111133
112134function import_wisdom (fname:: AbstractString )
135+ _init_ ()
113136 f = ccall (:fopen , Ptr{Void}, (Cstring,Cstring), fname, :r )
114137 systemerror (" could not open wisdom file $fname for reading" , f == C_NULL )
115138 if ccall ((:fftw_import_wisdom_from_file ,libfftw),Int32,(Ptr{Void},),f)== 0 ||
@@ -120,32 +143,23 @@ function import_wisdom(fname::AbstractString)
120143end
121144
122145function import_system_wisdom ()
146+ _init_ ()
123147 if ccall ((:fftw_import_system_wisdom ,libfftw), Int32, ()) == 0 ||
124148 ccall ((:fftwf_import_system_wisdom ,libfftwf), Int32, ()) == 0
125149 error (" failed to import system wisdom" )
126150 end
127151end
128152
129153function forget_wisdom ()
154+ _init_ ()
130155 ccall ((:fftw_forget_wisdom ,libfftw), Void, ())
131156 ccall ((:fftwf_forget_wisdom ,libfftwf), Void, ())
132157end
133158
134159# Threads
135160
136- const threads_initialized = Ref (false )
137161function set_num_threads (nthreads:: Integer )
138- if ! threads_initialized[]
139- # must forget wisdom if any FFTW routines have been called
140- # (don't call fftw_cleanup, since that would invalidate existing plans)
141- forget_wisdom ()
142- stat = ccall ((:fftw_init_threads ,libfftw), Int32, ())
143- statf = ccall ((:fftwf_init_threads ,libfftwf), Int32, ())
144- if stat == 0 || statf == 0
145- error (" could not initialize FFTW threads" )
146- end
147- threads_initialized[] = true
148- end
162+ _init_ ()
149163 ccall ((:fftw_plan_with_nthreads ,libfftw), Void, (Int32,), nthreads)
150164 ccall ((:fftwf_plan_with_nthreads ,libfftwf), Void, (Int32,), nthreads)
151165end
@@ -159,11 +173,15 @@ typealias PlanPtr Ptr{fftw_plan_struct}
159173
160174const NO_TIMELIMIT = - 1.0 # from fftw3.h
161175
162- set_timelimit (precision:: fftwTypeDouble ,seconds) =
176+ function set_timelimit (precision:: fftwTypeDouble ,seconds)
177+ _init_ ()
163178 ccall ((:fftw_set_timelimit ,libfftw), Void, (Float64,), seconds)
179+ end
164180
165- set_timelimit (precision:: fftwTypeSingle ,seconds) =
181+ function set_timelimit (precision:: fftwTypeSingle ,seconds)
182+ _init_ ()
166183 ccall ((:fftwf_set_timelimit ,libfftwf), Void, (Float64,), seconds)
184+ end
167185
168186# Array alignment mod 16:
169187# FFTW plans may depend on the alignment of the array mod 16 bytes,
0 commit comments