Skip to content

Commit a9c6d64

Browse files
authored
control global context (#141)
* add allow_global_context! * add test for allow_global_context! * add do block form of allow_global_context * add GEOSContext and allow_global_context! docs
1 parent 93855e0 commit a9c6d64

File tree

9 files changed

+335
-258
lines changed

9 files changed

+335
-258
lines changed

src/LibGEOS.jl

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,20 @@ function geosjl_errorhandler(message::Ptr{UInt8}, userdata)
107107
end
108108
end
109109

110+
"""
111+
112+
GEOSContext
113+
114+
Every LibGEOS object needs to live somewhere in memory. Also many LibGEOS functions
115+
need scratch memory or caches to do their job.
116+
117+
A `GEOSContext` governs such memory. Almost every function in LibGEOS accepts a `context`
118+
argument, that allows passing a context explicitly. If no context is passed, a global context is used.
119+
120+
Using the global context is fine, as long as no multi threading is used.
121+
If multi threading is used, the global context should be avoided and every operation should only
122+
involve objects that live in the context passed to the operation.
123+
"""
110124
mutable struct GEOSContext
111125
ptr::Ptr{Cvoid} # GEOSContextHandle_t
112126

@@ -123,7 +137,7 @@ mutable struct GEOSContext
123137
end
124138

125139
"Get a copy of a string from GEOS, freeing the GEOS managed memory."
126-
function string_copy_free(s::Cstring, context::Ptr{Cvoid} = _context.ptr)::String
140+
function string_copy_free(s::Cstring, context::Ptr{Cvoid} = get_global_context().ptr)::String
127141
copy = unsafe_string(s)
128142
GEOSFree_r(context, pointer(s))
129143
return copy
@@ -191,8 +205,50 @@ mutable struct WKBWriter
191205
end
192206
end
193207

208+
const _GLOBAL_CONTEXT = Ref{GEOSContext}()
209+
const _GLOBAL_CONTEXT_ALLOWED = Ref(false)
210+
211+
function get_global_context()::GEOSContext
212+
if _GLOBAL_CONTEXT_ALLOWED[]
213+
_GLOBAL_CONTEXT[]
214+
else
215+
msg = """
216+
LibGEOS global context disallowed, a `GEOSContext` must be passed explicitly.
217+
Alternatively you can allow the global context by calling:
218+
`LibGEOS.allow_global_context!(true)`
219+
"""
220+
error(msg)
221+
end
222+
end
223+
224+
"""
225+
226+
allow_global_context!(bool::Bool)
227+
228+
Allow (bool=true) or disallow (bool=false) using the global LibGEOS context.
229+
230+
231+
allow_global_context!(f, bool::Bool)
232+
233+
Call `f` with global context usage allowed according to `bool`
234+
235+
Generally this function should only be used as a debugging tool, mostly for multithreaded programs.
236+
See also [`GEOSContext`](@ref).
237+
"""
238+
function allow_global_context!(bool::Bool)
239+
_GLOBAL_CONTEXT_ALLOWED[] = bool
240+
end
241+
242+
function allow_global_context!(f, bool::Bool)
243+
old = _GLOBAL_CONTEXT_ALLOWED[]
244+
allow_global_context!(bool)
245+
f()
246+
allow_global_context!(old)
247+
end
248+
194249
function __init__()
195-
global _context = GEOSContext()
250+
_GLOBAL_CONTEXT_ALLOWED[] = true
251+
_GLOBAL_CONTEXT[] = GEOSContext()
196252
end
197253

198254
include("geos_functions.jl")

0 commit comments

Comments
 (0)