diff options
| author | Sergey Fedoseev <fedoseev.sergey@gmail.com> | 2015-12-23 14:35:17 +0500 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2015-12-23 08:02:37 -0500 |
| commit | 312fc1af7b8a028611b45ee272652d59ea7bd85a (patch) | |
| tree | a5a49b814592328424257d002ae0b4022b1750fc /django | |
| parent | febe1321dac489e2e9dc30b6a67ee3b623e0b735 (diff) | |
Fixed #25961 -- Removed handling of thread-non-safe GEOS functions.
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/gis/geos/libgeos.py | 46 | ||||
| -rw-r--r-- | django/contrib/gis/geos/prototypes/threadsafe.py | 93 |
2 files changed, 36 insertions, 103 deletions
diff --git a/django/contrib/gis/geos/libgeos.py b/django/contrib/gis/geos/libgeos.py index 500825a700..f4f93b57cc 100644 --- a/django/contrib/gis/geos/libgeos.py +++ b/django/contrib/gis/geos/libgeos.py @@ -9,12 +9,13 @@ import logging import os import re +import threading from ctypes import CDLL, CFUNCTYPE, POINTER, Structure, c_char_p from ctypes.util import find_library from django.contrib.gis.geos.error import GEOSException from django.core.exceptions import ImproperlyConfigured -from django.utils.functional import SimpleLazyObject +from django.utils.functional import SimpleLazyObject, cached_property logger = logging.getLogger('django.contrib.gis') @@ -63,10 +64,11 @@ def load_geos(): _lgeos = CDLL(lib_path) # Here we set up the prototypes for the initGEOS_r and finishGEOS_r # routines. These functions aren't actually called until they are - # attached to a GEOS context handle -- this actually occurs in - # geos/prototypes/threadsafe.py. + # attached to a GEOS context handle. _lgeos.initGEOS_r.restype = CONTEXT_PTR _lgeos.finishGEOS_r.argtypes = [CONTEXT_PTR] + # Ensures compatibility across 32 and 64-bit platforms. + _lgeos.GEOSversion.restype = c_char_p return _lgeos @@ -134,6 +136,27 @@ def get_pointer_arr(n): lgeos = SimpleLazyObject(load_geos) +class GEOSContextHandle(object): + def __init__(self): + # Initializing the context handle for this thread with + # the notice and error handler. + self.ptr = lgeos.initGEOS_r(notice_h, error_h) + + def __del__(self): + if self.ptr and lgeos: + lgeos.finishGEOS_r(self.ptr) + + +class GEOSContext(threading.local): + + @cached_property + def ptr(self): + # Assign handle so it will will garbage collected when + # thread is finished. + self.handle = GEOSContextHandle() + return self.handle.ptr + + class GEOSFuncFactory(object): """ Lazy loading of GEOS functions. @@ -141,6 +164,7 @@ class GEOSFuncFactory(object): argtypes = None restype = None errcheck = None + thread_context = GEOSContext() def __init__(self, func_name, *args, **kwargs): self.func_name = func_name @@ -154,21 +178,23 @@ class GEOSFuncFactory(object): def __call__(self, *args, **kwargs): if self.func is None: self.func = self.get_func(*self.args, **self.kwargs) - return self.func(*args, **kwargs) + # Call the threaded GEOS routine with pointer of the context handle + # as the first argument. + return self.func(self.thread_context.ptr, *args) def get_func(self, *args, **kwargs): - from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc - func = GEOSFunc(self.func_name) - func.argtypes = self.argtypes or [] + # GEOS thread-safe function signatures end with '_r' and + # take an additional context handle parameter. + func = getattr(lgeos, self.func_name + '_r') + func.argtypes = [CONTEXT_PTR] + (self.argtypes or []) func.restype = self.restype if self.errcheck: func.errcheck = self.errcheck return func -# Returns the string version of the GEOS library. Have to set the restype -# explicitly to c_char_p to ensure compatibility across 32 and 64-bit platforms. -geos_version = GEOSFuncFactory('GEOSversion', restype=c_char_p) +# Returns the string version of the GEOS library. +geos_version = lambda: lgeos.GEOSversion() # Regular expression should be able to parse version strings such as # '3.0.0rc4-CAPI-1.3.3', '3.0.0-CAPI-1.4.1', '3.4.0dev-CAPI-1.8.0' or '3.4.0dev-CAPI-1.8.0 r0' diff --git a/django/contrib/gis/geos/prototypes/threadsafe.py b/django/contrib/gis/geos/prototypes/threadsafe.py deleted file mode 100644 index 45c87d6004..0000000000 --- a/django/contrib/gis/geos/prototypes/threadsafe.py +++ /dev/null @@ -1,93 +0,0 @@ -import threading - -from django.contrib.gis.geos.libgeos import ( - CONTEXT_PTR, error_h, lgeos, notice_h, -) - - -class GEOSContextHandle(object): - """ - Python object representing a GEOS context handle. - """ - def __init__(self): - # Initializing the context handler for this thread with - # the notice and error handler. - self.ptr = lgeos.initGEOS_r(notice_h, error_h) - - def __del__(self): - if self.ptr and lgeos: - lgeos.finishGEOS_r(self.ptr) - - -# Defining a thread-local object and creating an instance -# to hold a reference to GEOSContextHandle for this thread. -class GEOSContext(threading.local): - handle = None - -thread_context = GEOSContext() - - -class GEOSFunc(object): - """ - Class that serves as a wrapper for GEOS C Functions, and will - use thread-safe function variants when available. - """ - def __init__(self, func_name): - try: - # GEOS thread-safe function signatures end with '_r', and - # take an additional context handle parameter. - self.cfunc = getattr(lgeos, func_name + '_r') - self.threaded = True - # Create a reference here to thread_context so it's not - # garbage-collected before an attempt to call this object. - self.thread_context = thread_context - except AttributeError: - # Otherwise, use usual function. - self.cfunc = getattr(lgeos, func_name) - self.threaded = False - - def __call__(self, *args): - if self.threaded: - # If a context handle does not exist for this thread, initialize one. - if not self.thread_context.handle: - self.thread_context.handle = GEOSContextHandle() - # Call the threaded GEOS routine with pointer of the context handle - # as the first argument. - return self.cfunc(self.thread_context.handle.ptr, *args) - else: - return self.cfunc(*args) - - def __str__(self): - return self.cfunc.__name__ - - # argtypes property - def _get_argtypes(self): - return self.cfunc.argtypes - - def _set_argtypes(self, argtypes): - if self.threaded: - new_argtypes = [CONTEXT_PTR] - new_argtypes.extend(argtypes) - self.cfunc.argtypes = new_argtypes - else: - self.cfunc.argtypes = argtypes - - argtypes = property(_get_argtypes, _set_argtypes) - - # restype property - def _get_restype(self): - return self.cfunc.restype - - def _set_restype(self, restype): - self.cfunc.restype = restype - - restype = property(_get_restype, _set_restype) - - # errcheck property - def _get_errcheck(self): - return self.cfunc.errcheck - - def _set_errcheck(self, errcheck): - self.cfunc.errcheck = errcheck - - errcheck = property(_get_errcheck, _set_errcheck) |
