From 39feec4e351248e62c81d80f34095b38cbe45a2c Mon Sep 17 00:00:00 2001 From: Clemens Vasters Date: Tue, 9 Dec 2025 08:08:15 +0100 Subject: [PATCH] C SDK: Document thread safety and fix js_cleanup to clear regex cache - Add Thread Safety section to README documenting safe usage patterns - Fix js_cleanup() to call js_regex_cache_clear() before resetting allocator - Document what is and isn't thread-safe Fixes #23 --- c/README.md | 57 +++++++++++++++++++++++++++++++++++++ c/src/json_source_locator.c | 4 +++ 2 files changed, 61 insertions(+) diff --git a/c/README.md b/c/README.md index c75666b..9d54499 100644 --- a/c/README.md +++ b/c/README.md @@ -225,6 +225,63 @@ c/ MIT License. See [LICENSE](LICENSE) for details. +## Thread Safety + +The C SDK is **partially thread-safe** with the following requirements: + +### Safe Usage Pattern + +1. **Call `js_init()` once** before spawning any threads that use the library +2. **Never call `js_set_allocator()`** while any thread is performing validation +3. **Each thread must use its own `js_result_t`** - do not share result structs across threads +4. **Call `js_cleanup()` once** after all threads have finished + +### What Is Thread-Safe + +- Concurrent calls to `js_validate_schema()` and `js_validate_instance()` from multiple threads (with separate result buffers) +- The compiled regex cache is protected by a mutex +- All read-only lookup tables (type names, error messages) + +### What Is NOT Thread-Safe + +- Calling `js_set_allocator()` or `js_cleanup()` while validations are in progress +- Sharing `js_result_t` structs between threads +- Calling `js_init_with_allocator()` from multiple threads + +### Example Multi-threaded Usage + +```c +#include +#include + +void* validate_thread(void* arg) { + const char* schema = (const char*)arg; + js_result_t result; // Thread-local result + + js_validate_schema(schema, &result); + // Process result... + js_result_cleanup(&result); + + return NULL; +} + +int main(void) { + js_init(); // Initialize once before threads + + pthread_t threads[4]; + for (int i = 0; i < 4; i++) { + pthread_create(&threads[i], NULL, validate_thread, schema); + } + + for (int i = 0; i < 4; i++) { + pthread_join(threads[i], NULL); + } + + js_cleanup(); // Cleanup once after all threads complete + return 0; +} +``` + ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines. diff --git a/c/src/json_source_locator.c b/c/src/json_source_locator.c index 973f065..dac6d3f 100644 --- a/c/src/json_source_locator.c +++ b/c/src/json_source_locator.c @@ -11,6 +11,7 @@ #include "json_structure/json_structure.h" #include "json_structure/types.h" +#include "regex_utils.h" #include #include #include @@ -395,6 +396,9 @@ void js_init_with_allocator(js_allocator_t alloc) { } void js_cleanup(void) { + /* Clear the regex cache before resetting allocator */ + js_regex_cache_clear(); + /* Reset to default allocator */ js_allocator_t default_alloc = {NULL, NULL, NULL, NULL}; js_set_allocator(default_alloc);