You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2025/08/03 19:53:15 UTC
(celix) 01/01: Add SBRM documentation
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/update-doc-for-SBRM
in repository https://gitbox.apache.org/repos/asf/celix.git
commit 68af694da634d31c933dfb5bfcf8b1615a288f09
Author: Pepijn Noltes <pn...@apache.org>
AuthorDate: Sun Aug 3 21:52:38 2025 +0200
Add SBRM documentation
---
documents/README.md | 1 +
documents/SBRM.md | 84 +++++++++++++++++++++++++++++++++++++++++
documents/development/README.md | 62 ++++++++++++++++++------------
3 files changed, 122 insertions(+), 25 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..d6364f523
--- /dev/null
+++ b/documents/SBRM.md
@@ -0,0 +1,84 @@
+---
+title: Apache Celix Auto Pointers
+---
+
+<!--
+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.
+-->
+
+# Apache Celix 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..3b5587fd5 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,50 @@ 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;
+ bool mutexInitialized;
+ 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_autoptr(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));
-
+
+ if (celixThreadMutex_create(&foo->mutex, NULL) == CELIX_SUCCESS) {
+ foo->mutexInitialized = true;
+ } else {
+ celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR,
+ "Error creating mutex");
+ return NULL; //foo cleaned up automatically
+ }
+
foo->list = celix_arrayList_create();
foo->map = celix_longHashMap_create();
- if (!foo->list || !foo->map) {
- goto create_enomem_err;
+ if (!foo->list || !foo->map) {
+ celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR,
+ "Error creating foo, out of memory");
+ return NULL; //foo cleaned up automatically
}
-
- 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;
+
+ 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->mutexInitialized) {
+ celixThreadMutex_destroy(&foo->mutex);
+ }
celix_arrayList_destroy(foo->list);
celix_longHashMap_destroy(foo->map);
free(foo);