This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/celix.git


The following commit(s) were added to refs/heads/master by this push:
     new 712c1040b Add SBRM documentation
712c1040b is described below

commit 712c1040bbf8671713837890579adde9505bbb49
Author: Pepijn Noltes <pnol...@apache.org>
AuthorDate: Mon Aug 18 20:41:59 2025 +0200

    Add SBRM documentation
    
    ---------
    
    Co-authored-by: PengZheng <howto...@gmail.com>
---
 documents/README.md             |  1 +
 documents/SBRM.md               | 84 +++++++++++++++++++++++++++++++++++++++++
 documents/development/README.md | 65 +++++++++++++++++--------------
 3 files changed, 122 insertions(+), 28 deletions(-)

diff --git a/documents/README.md b/documents/README.md
index c174acbe7..fefec7971 100644
--- a/documents/README.md
+++ b/documents/README.md
@@ -98,3 +98,4 @@ bundles contains binaries depending on the stdlibc++ library.
 * [Apache Celix CMake Commands](cmake_commands)
 * [Apache Celix Sub Projects](subprojects.md)
 * [Apache Celix Coding Conventions Guide](development/README.md)
+* [Apache Celix Scope Bound Resource Management](SBRM.md)
diff --git a/documents/SBRM.md b/documents/SBRM.md
new file mode 100644
index 000000000..c4da9aa2f
--- /dev/null
+++ b/documents/SBRM.md
@@ -0,0 +1,84 @@
+---
+title: Scope-Based Resource Management
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Scope-Based Resource Management (SBRM)
+
+Apache Celix provides *auto pointers* and *auto values* as a lightweight form 
of scope-based resource management in C. 
+These features are inspired by the RAII (Resource Acquisition Is 
Initialization) paradigm from C++, 
+as well as ideas from [Scope-based resource management for the 
kernel](https://lwn.net/Articles/934679/).
+
+Using the macros defined in `celix_cleanup.h` and related headers 
(`celix_stdio_cleanup.h`, `celix_stdlib_cleanup.h`), 
+resources are automatically released when their associated variables go out of 
scope. This enables safer and more 
+concise C code, especially when handling early returns or error paths.
+
+## Defining Cleanup Functions
+
+Before using auto cleanup, types must opt-in by defining a cleanup function.
+
+- For pointer types:
+
+```C
+  CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_filter_t, celix_filter_destroy)
+```
+
+- For value types:
+
+```C
+CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_mutex_lock_guard_t, 
celixMutexLockGuard_deinit)
+```
+
+## Using Auto Pointers and Auto Values
+
+### Auto Pointers
+
+Use `celix_autoptr(type)` to declare a pointer that will be cleaned up 
automatically:
+
+```C
+void my_function(void) {
+    celix_autoptr(celix_filter_t) filter = celix_filter_create("(foo=bar)");
+    // use filter
+} // filter is destroyed automatically
+```
+
+To transfer ownership and disable automatic cleanup, use:
+
+```C
+celix_filter_t* raw = celix_steal_ptr(filter);
+```
+
+### Auto Values
+
+Use `celix_auto(type)` to declare a value-based resource with automatic 
cleanup:
+
+```C
+void my_function(void) {
+    celix_auto(celix_mutex_lock_guard_t) lock = 
celixMutexLockGuard_init(&myMutex);
+    // use guarded memory
+} // lock guard is cleaned up automatically (myMutex is unlocked)
+```
+
+## Benefits
+
+Celix's SBRM features allow for:
+
+- Simplified cleanup logic
+- RAII-style early returns
+- Cleaner, more maintainable C code
diff --git a/documents/development/README.md b/documents/development/README.md
index e1f4a99a2..d521acb34 100644
--- a/documents/development/README.md
+++ b/documents/development/README.md
@@ -333,10 +333,8 @@ add_library(celix::MyBundle ALIAS MyBundle)
 - Use `while` statements for loops that may not execute.
 - Use `do`/`while` statements for loops that must execute at least once.
 - Use `for` statements for loops with a known number of iterations.
-- The use of `goto` is not allowed, except for error handling in C (for C++ 
use RAII).
-- For C, try to prevent deeply nested control structures and prefer early 
returns or error handling `goto` statements.
-  - To prevent deeply nested control structures, the `CELIX_DO_IF`, 
`CELIX_GOTO_IF_NULL` and `CELIX_GOTO_IF_ERR` 
-    macros can also be used.
+- Avoid using `goto` for error handling. Prefer early returns and automatic 
cleanup using celix auto pointers.
+- To prevent deeply nested control structures, the `CELIX_DO_IF` macro can 
also be used.
 
 ## Functions and Methods
 
@@ -350,7 +348,7 @@ add_library(celix::MyBundle ALIAS MyBundle)
 - For C++ functions with a lot of different parameters, consider using a 
builder pattern.
   - A builder pattern can be updated backwards compatible.
   - A builder pattern ensure that a lot of parameters can be configured, but 
also direct set on construction.
- 
+
 ## Error Handling and Logging
 
 - For C++, throw an exception when an error occurs and use RAII to ensure that 
resources are freed.
@@ -362,9 +360,10 @@ add_library(celix::MyBundle ALIAS MyBundle)
 - Use consistent error handling techniques, such as returning error codes or 
using designated error handling functions.
 - Log errors, warnings, and other important events using the Apache Celix log 
helper functions or - for libraries - 
   the `celix_err` functionality. 
-- Always check for errors and log them. 
+- Always check for errors and log them.
 - Error handling should free resources in the reverse order of their 
allocation/creation.
 - Ensure error handling is correct, using test suite with error injection.
+ - Prefer early returns together with celix auto pointers to ensure cleanup 
without using `goto`.
 
 For log levels use the following guidelines:
 - trace: Use this level for very detailed that you would only want to have 
while diagnosing problems. 
@@ -381,37 +380,47 @@ For log levels use the following guidelines:
 - fatal: Use this level to report severe errors that prevent the program from 
continuing to run. 
   After logging a fatal error, the program will typically terminate.
 
-Example of error handling and logging:
+Example of error handling and logging using auto pointers:
 ```c
+typedef struct celix_foo {
+    celix_thread_mutex_t mutex;
+    celix_array_list_t* list;
+    celix_long_hash_map_t* map;
+} celix_foo_t;
+
+CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_foo_t, celix_foo_destroy)
+
 celix_foo_t* celix_foo_create(celix_log_helper_t* logHelper) {
-    celix_foo_t* foo = calloc(1, sizeof(*foo));
+    celix_autofree celix_foo_t* foo = calloc(1, sizeof(*foo));
     if (!foo) {
-        goto create_enomem_err;
+        celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR,
+                "Error creating foo, out of memory");
+        return NULL;
     }
-    
-    CELIX_GOTO_IF_ERR(create_mutex_err, celixThreadMutex_create(&foo->mutex, 
NULL));
-    
-    foo->list = celix_arrayList_create();
-    foo->map = celix_longHashMap_create();
-    if (!foo->list ||  !foo->map) {
-        goto create_enomem_err;
+
+    if (celixThreadMutex_create(&foo->mutex, NULL) != CELIX_SUCCESS) {
+        celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR,
+                "Error creating mutex");
+        return NULL; //foo cleaned up automatically (celix_autofree will call 
free)
     }
     
-  return foo;
-create_mutex_err:
-  celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR, "Error creating 
mutex");
-  free(foo); //mutex not created, do not use celix_foo_destroy to prevent 
mutex destroy
-  return NULL;
-create_enomem_err:
-  celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR, "Error creating foo, 
out of memory");
-  celix_foo_destroy(foo); //note celix_foo_destroy can handle NULL
-  return NULL;
+    celix_autoptr(celix_thread_mutex_t) mutex = &foo->mutex;
+    celix_autoptr(celix_array_list_t) list = celix_arrayList_create();
+    celix_autoptr(celix_long_hash_map_t) map = celix_longHashMap_create();
+    if (!list || !map) {
+        celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR,
+                "Error creating foo, out of memory");
+        return NULL; //foo, list and/or map are cleaned up automatically
+    }
+
+    celix_steal_ptr(mutex);
+    foo->list = celix_steal_ptr(list);
+    foo->map = celix_steal_ptr(map);
+    return celix_steal_ptr(foo);
 }
 
 void celix_foo_destroy(celix_foo_t* foo) {
-    if (foo != NULL) {
-        //note reverse order of creation
-        celixThreadMutex_destroy(&foo->mutex);
+    if (foo) {
         celix_arrayList_destroy(foo->list);
         celix_longHashMap_destroy(foo->map);
         free(foo);

Reply via email to