From 4841c0750219115cd67da78e9981f7900d9c86ff Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Thu, 12 Mar 2026 11:40:06 +0100 Subject: [PATCH 1/2] lib/external/parson: use G_malloc and G_free internally - libgrass_parson library now depends on libgrass_gis - wrap G_malloc in private function adapting to G__parson_malloc - G_json_value_init_object and G_json_value_init_array always return allocated object - parson is initialized lazily using C11 atomic operation --- include/Make/Grass.make | 1 + lib/CMakeLists.txt | 2 +- lib/Makefile | 1 + lib/external/Makefile | 1 - lib/external/parson/gjson.c | 82 +++++++++++++++++++++++++++++++++++++ lib/external/parson/gjson.h | 6 ++- 6 files changed, 89 insertions(+), 4 deletions(-) diff --git a/include/Make/Grass.make b/include/Make/Grass.make index 5a1e8cba7d3..e89f8d1dd49 100644 --- a/include/Make/Grass.make +++ b/include/Make/Grass.make @@ -209,6 +209,7 @@ LRSDEPS = $(DBMILIB) $(GISLIB) MANAGEDEPS = $(VECTORLIB) $(GISLIB) NVIZDEPS = $(OGSFLIB) $(GISLIB) $(OPENGLLIB) OGSFDEPS = $(BITMAPLIB) $(RASTER3DLIB) $(VECTORLIB) $(DBMILIB) $(RASTERLIB) $(GISLIB) $(TIFFLIBPATH) $(TIFFLIB) $(OPENGLLIB) $(OPENGLULIB) $(MATHLIB) +PARSONDEPS = $(GISLIB) PNGDRIVERDEPS = $(DRIVERLIB) $(GISLIB) $(PNGLIB) $(MATHLIB) PSDRIVERDEPS = $(DRIVERLIB) $(GISLIB) $(MATHLIB) RASTERDEPS = $(GISLIB) $(GPROJLIB) $(MATHLIB) $(PARSONLIB) $(GDALLIBS) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 3478b1d4534..79f754a97aa 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -19,7 +19,7 @@ build_library_in_subdir( add_subdirectory(proj) -build_library_in_subdir(external/parson NAME grass_parson HEADERS "gjson.h") +build_library_in_subdir(external/parson NAME grass_parson DEPENDS grass_gis HEADERS "gjson.h") build_program_in_subdir(external/parson/test NAME test.gjson.lib DEPENDS grass_gis grass_parson) build_library_in_subdir( diff --git a/lib/Makefile b/lib/Makefile index 96a23af2069..1dc3766b3f9 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -8,6 +8,7 @@ SUBDIRS = \ datetime \ gis \ proj \ + external/parson \ raster \ gmath \ linkm \ diff --git a/lib/external/Makefile b/lib/external/Makefile index 6c28110144c..5453bb931f0 100644 --- a/lib/external/Makefile +++ b/lib/external/Makefile @@ -3,7 +3,6 @@ MODULE_TOPDIR = ../.. SUBDIRS = \ ccmath \ - parson \ shapelib include $(MODULE_TOPDIR)/include/Make/Dir.make diff --git a/lib/external/parson/gjson.c b/lib/external/parson/gjson.c index cb5cd0305eb..1591d628a35 100644 --- a/lib/external/parson/gjson.c +++ b/lib/external/parson/gjson.c @@ -15,6 +15,11 @@ * *****************************************************************************/ +#include +#include + +#include + #include "gjson.h" #include "parson.h" @@ -22,38 +27,84 @@ typedef struct json_object_t G_json_object_t; typedef struct json_array_t G_json_array_t; typedef struct json_value_t G_json_value_t; +#define G_PARSON_MALLOC_ATTR \ + G_ATTR_MALLOC G_ATTR_ALLOC_SIZE1(1) G_ATTR_OWNSHIP_RET G_ATTR_RET_NONNULL + +static void *G__parson_malloc(size_t size) G_PARSON_MALLOC_ATTR; + +static void *G__parson_malloc(size_t size) +{ + return G_malloc(size); +} + +#undef G_PARSON_MALLOC_ATTR + +typedef enum { UNINITIALIZED, INITIALIZING, INITIALIZED } init_state_t; + +static _Atomic int parson_init_state = UNINITIALIZED; + +void ensure_parson_initialized(void) +{ + if (atomic_load_explicit(&parson_init_state, memory_order_acquire) == + INITIALIZED) { + return; + } + + int expected = UNINITIALIZED; + + if (atomic_compare_exchange_strong(&parson_init_state, &expected, + INITIALIZING)) { + + json_set_allocation_functions(G__parson_malloc, G_free); + + atomic_store_explicit(&parson_init_state, INITIALIZED, + memory_order_release); + } + else { + while (atomic_load_explicit(&parson_init_state, memory_order_acquire) != + INITIALIZED) + ; + } +} + /* *************************************************************** */ /* ***** WRAPPER FOR PARSON FUNCTIONS USED IN GRASS ************** */ /* *************************************************************** */ G_JSON_Value *G_json_value_init_object(void) { + ensure_parson_initialized(); return (G_JSON_Value *)json_value_init_object(); } G_JSON_Value *G_json_value_init_array(void) { + ensure_parson_initialized(); return (G_JSON_Value *)json_value_init_array(); } G_JSON_Value_Type G_json_value_get_type(const G_JSON_Value *value) { + ensure_parson_initialized(); return json_value_get_type((const JSON_Value *)value); } G_JSON_Object *G_json_value_get_object(const G_JSON_Value *value) { + ensure_parson_initialized(); return (G_JSON_Object *)json_value_get_object((const JSON_Value *)value); } G_JSON_Object *G_json_object(const G_JSON_Value *value) { + ensure_parson_initialized(); return (G_JSON_Object *)json_object((const JSON_Value *)value); } G_JSON_Object *G_json_object_get_object(const G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return (G_JSON_Object *)json_object_get_object((const JSON_Object *)object, name); } @@ -61,6 +112,7 @@ G_JSON_Object *G_json_object_get_object(const G_JSON_Object *object, G_JSON_Array *G_json_object_get_array(const G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return (G_JSON_Array *)json_object_get_array((const JSON_Object *)object, name); } @@ -68,6 +120,7 @@ G_JSON_Array *G_json_object_get_array(const G_JSON_Object *object, G_JSON_Value *G_json_object_get_value(const G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return (G_JSON_Value *)json_object_get_value((const JSON_Object *)object, name); } @@ -75,152 +128,181 @@ G_JSON_Value *G_json_object_get_value(const G_JSON_Object *object, const char *G_json_object_get_string(const G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return json_object_get_string((const JSON_Object *)object, name); } double G_json_object_get_number(const G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return json_object_get_number((const JSON_Object *)object, name); } int G_json_object_get_boolean(const G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return json_object_get_boolean((const JSON_Object *)object, name); } G_JSON_Value *G_json_object_get_wrapping_value(const G_JSON_Object *object) { + ensure_parson_initialized(); return (G_JSON_Value *)json_object_get_wrapping_value( (const JSON_Object *)object); } G_JSON_Status G_json_object_set_value(G_JSON_Object *object, const char *name, G_JSON_Value *value) { + ensure_parson_initialized(); return json_object_set_value((JSON_Object *)object, name, (JSON_Value *)value); } G_JSON_Status G_json_object_set_string(G_JSON_Object *object, const char *name, const char *string) { + ensure_parson_initialized(); return json_object_set_string((JSON_Object *)object, name, string); } G_JSON_Status G_json_object_set_number(G_JSON_Object *object, const char *name, double number) { + ensure_parson_initialized(); return json_object_set_number((JSON_Object *)object, name, number); } G_JSON_Status G_json_object_set_boolean(G_JSON_Object *object, const char *name, int boolean) { + ensure_parson_initialized(); return json_object_set_boolean((JSON_Object *)object, name, boolean); } G_JSON_Status G_json_object_set_null(G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return json_object_set_null((JSON_Object *)object, name); } G_JSON_Status G_json_object_dotset_string(G_JSON_Object *object, const char *name, const char *string) { + ensure_parson_initialized(); return json_object_dotset_string((JSON_Object *)object, name, string); } const char *G_json_object_dotget_string(G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return json_object_dotget_string((JSON_Object *)object, name); } G_JSON_Status G_json_object_dotset_number(G_JSON_Object *object, const char *name, double number) { + ensure_parson_initialized(); return json_object_dotset_number((JSON_Object *)object, name, number); } double G_json_object_dotget_number(G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return json_object_dotget_number((JSON_Object *)object, name); } G_JSON_Status G_json_object_dotset_null(G_JSON_Object *object, const char *name) { + ensure_parson_initialized(); return json_object_dotset_null((JSON_Object *)object, name); } G_JSON_Array *G_json_array(const G_JSON_Value *value) { + ensure_parson_initialized(); return (G_JSON_Array *)json_array((const JSON_Value *)value); } G_JSON_Value *G_json_array_get_value(const G_JSON_Array *array, size_t index) { + ensure_parson_initialized(); return (G_JSON_Value *)json_array_get_value((const JSON_Array *)array, index); } const char *G_json_array_get_string(const G_JSON_Array *array, size_t index) { + ensure_parson_initialized(); return json_array_get_string((const JSON_Array *)array, index); } double G_json_array_get_number(const G_JSON_Array *array, size_t index) { + ensure_parson_initialized(); return json_array_get_number((const JSON_Array *)array, index); } int G_json_array_get_boolean(const G_JSON_Array *array, size_t index) { + ensure_parson_initialized(); return json_array_get_boolean((const JSON_Array *)array, index); } G_JSON_Status G_json_array_append_value(G_JSON_Array *array, G_JSON_Value *value) { + ensure_parson_initialized(); return json_array_append_value((JSON_Array *)array, (JSON_Value *)value); } G_JSON_Status G_json_array_append_string(G_JSON_Array *array, const char *string) { + ensure_parson_initialized(); return json_array_append_string((JSON_Array *)array, string); } G_JSON_Status G_json_array_append_number(G_JSON_Array *array, double number) { + ensure_parson_initialized(); return json_array_append_number((JSON_Array *)array, number); } G_JSON_Status G_json_array_append_boolean(G_JSON_Array *array, int boolean) { + ensure_parson_initialized(); return json_array_append_boolean((JSON_Array *)array, boolean); } G_JSON_Status G_json_array_append_null(G_JSON_Array *array) { + ensure_parson_initialized(); return json_array_append_null((JSON_Array *)array); } void G_json_set_float_serialization_format(const char *format) { + ensure_parson_initialized(); json_set_float_serialization_format(format); } char *G_json_serialize_to_string_pretty(const G_JSON_Value *value) { + ensure_parson_initialized(); return json_serialize_to_string_pretty((const JSON_Value *)value); } char *G_json_serialize_to_string(const G_JSON_Value *value) { + ensure_parson_initialized(); return json_serialize_to_string((const JSON_Value *)value); } void G_json_free_serialized_string(char *string) { + ensure_parson_initialized(); json_free_serialized_string(string); } void G_json_value_free(G_JSON_Value *value) { + ensure_parson_initialized(); json_value_free((JSON_Value *)value); } diff --git a/lib/external/parson/gjson.h b/lib/external/parson/gjson.h index 872e1c5ed88..e7021e342b0 100644 --- a/lib/external/parson/gjson.h +++ b/lib/external/parson/gjson.h @@ -3,6 +3,8 @@ #include +#include + /* *************************************************************** */ /* ***** WRAPPER FOR PARSON FUNCTIONS USED IN GRASS ************** */ /* *************************************************************** */ @@ -25,8 +27,8 @@ typedef int G_JSON_Value_Type; enum g_json_result_t { G_JSONSuccess = 0, G_JSONFailure = -1 }; typedef int G_JSON_Status; -extern G_JSON_Value *G_json_value_init_object(void); -extern G_JSON_Value *G_json_value_init_array(void); +extern G_JSON_Value *G_json_value_init_object(void) G_ATTR_RET_NONNULL; +extern G_JSON_Value *G_json_value_init_array(void) G_ATTR_RET_NONNULL; extern G_JSON_Value_Type G_json_value_get_type(const G_JSON_Value *value); extern G_JSON_Object *G_json_value_get_object(const G_JSON_Value *); From effa8879ff4c88c35ae874554329689e80d6debb Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Mon, 23 Mar 2026 08:48:14 +0100 Subject: [PATCH 2/2] add fallback if atomic operations are not supported --- lib/external/parson/gjson.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/external/parson/gjson.c b/lib/external/parson/gjson.c index 1591d628a35..e102623f4b4 100644 --- a/lib/external/parson/gjson.c +++ b/lib/external/parson/gjson.c @@ -15,8 +15,9 @@ * *****************************************************************************/ +#ifndef __STDC_NO_ATOMICS__ #include -#include +#endif #include @@ -39,12 +40,21 @@ static void *G__parson_malloc(size_t size) #undef G_PARSON_MALLOC_ATTR +#if defined __STDC_NO_ATOMICS__ +static volatile int parson_initialized = 0; +#else typedef enum { UNINITIALIZED, INITIALIZING, INITIALIZED } init_state_t; - static _Atomic int parson_init_state = UNINITIALIZED; +#endif void ensure_parson_initialized(void) { +#if defined __STDC_NO_ATOMICS__ + if (!parson_initialized) { + json_set_allocation_functions(G__parson_malloc, G_free); + parson_initialized = 1; + } +#else if (atomic_load_explicit(&parson_init_state, memory_order_acquire) == INITIALIZED) { return; @@ -65,6 +75,7 @@ void ensure_parson_initialized(void) INITIALIZED) ; } +#endif } /* *************************************************************** */