|
1 | 1 | module T8code |
2 | 2 |
|
| 3 | +using MPI |
| 4 | + |
3 | 5 | using Reexport: @reexport |
4 | 6 | using Libdl: Libdl |
5 | 7 |
|
@@ -157,6 +159,85 @@ not a system-provided `t8code` installation. In this case, T8code.jl is not usab |
157 | 159 | preferences_set_correctly() = !(_PREFERENCE_LIBT8 == "t8code_jll" && |
158 | 160 | MPIPreferences.binary == "system") |
159 | 161 |
|
| 162 | +""" |
| 163 | + ForestWrapper |
| 164 | +
|
| 165 | +Lightweight `t8_forest_t` pointer wrapper which helps to free |
| 166 | +resources allocated by t8code in an orderly fashion. |
| 167 | +
|
| 168 | +When initialized with a t8code forest pointer the wrapper |
| 169 | +registers itself with a t8code object tracker called `T8CODE_OBJECT_TRACKER`. |
| 170 | +
|
| 171 | +In serial mode the wrapper and in consequence the t8code forest |
| 172 | +can be finalized immediately whenever Julia's garbage collector sees fit. |
| 173 | +
|
| 174 | +In (MPI) parallel mode the wrapper (and the t8code forest) is kept till the end |
| 175 | +of the session or when finalized explicitly. At the end of the session (resp. |
| 176 | +when the program shuts down) the object tracker finalizes all registered t8code |
| 177 | +objects in sync with all MPI ranks. This is necessary since t8code internally |
| 178 | +allocates MPI shared arrays. |
| 179 | +""" |
| 180 | +mutable struct ForestWrapper |
| 181 | + pointer::Ptr{t8_forest} # cpointer to t8code forest |
| 182 | + |
| 183 | + function ForestWrapper(pointer::Ptr{t8_forest}) |
| 184 | + wrapper = new(pointer) |
| 185 | + |
| 186 | + # Compute a unique id from the ForestWrapper object. |
| 187 | + unique_id = UInt64(pointer_from_objref(wrapper)) |
| 188 | + |
| 189 | + if MPI.Comm_size(MPI.Comm(t8_forest_get_mpicomm(pointer))) > 1 |
| 190 | + # Make sure the unique id is identical for each MPI rank. |
| 191 | + unique_id = MPI.bcast(unique_id, MPI.Comm(t8_forest_get_mpicomm(pointer))) |
| 192 | + end |
| 193 | + |
| 194 | + finalizer(wrapper) do wrapper |
| 195 | + # When finalizing, `forest`, `scheme`, `cmesh`, and `geometry` are |
| 196 | + # also cleaned up from within `t8code`. The cleanup code for |
| 197 | + # `cmesh` does some MPI calls for deallocating shared memory |
| 198 | + # arrays. Due to garbage collection in Julia the order of shutdown |
| 199 | + # is not deterministic. Hence, deterministic finalization is necessary in |
| 200 | + # order to avoid MPI-related error output when closing the Julia |
| 201 | + # program/session. |
| 202 | + t8_forest_unref(Ref(wrapper.pointer)) |
| 203 | + |
| 204 | + # Deregister from the object tracker. |
| 205 | + delete!(T8CODE_OBJECT_TRACKER, unique_id) |
| 206 | + end |
| 207 | + |
| 208 | + # Register the T8codeForestWrapper with the object tracker. |
| 209 | + T8CODE_OBJECT_TRACKER[unique_id] = wrapper |
| 210 | + |
| 211 | + return wrapper |
| 212 | + end |
| 213 | +end |
| 214 | + |
| 215 | +function clean_up() |
| 216 | + # Finalize all registered t8code objects before MPI shuts down. |
| 217 | + while length(T8CODE_OBJECT_TRACKER) > 0 |
| 218 | + unique_id = first(T8CODE_OBJECT_TRACKER).first |
| 219 | + |
| 220 | + forest_wrapper = T8CODE_OBJECT_TRACKER[unique_id] |
| 221 | + |
| 222 | + # Make sure all MPI ranks finalize the same object. |
| 223 | + if MPI.Comm_size(MPI.Comm(t8_forest_get_mpicomm(forest_wrapper.pointer))) > 1 |
| 224 | + unique_id = MPI.bcast(unique_id, |
| 225 | + MPI.Comm(t8_forest_get_mpicomm(forest_wrapper.pointer))) |
| 226 | + end |
| 227 | + |
| 228 | + # Finalize the object. The object deregisters itself from the |
| 229 | + # object tracker automatically. |
| 230 | + finalize(forest_wrapper) |
| 231 | + end |
| 232 | +end |
| 233 | + |
| 234 | +# Minimal reference tracker holding active t8code related objects |
| 235 | +# created throughout the life time of a Julia session. t8code objects |
| 236 | +# should remove themselves from the tracker when they get finalized. |
| 237 | +if !@isdefined(T8CODE_OBJECT_TRACKER) |
| 238 | + T8CODE_OBJECT_TRACKER = Dict{UInt64, ForestWrapper}() |
| 239 | +end |
| 240 | + |
160 | 241 | const T8_QUAD_MAXLEVEL = 30 |
161 | 242 | const T8_HEX_MAXLEVEL = 19 |
162 | 243 |
|
|
0 commit comments