This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/celix_err in repository https://gitbox.apache.org/repos/asf/celix.git
commit c4b9d723a54762908396123ab879d19e028a9ced Author: Pepijn Noltes <[email protected]> AuthorDate: Mon May 1 19:58:59 2023 +0200 Add initial implementation for celix_err --- libs/utils/CMakeLists.txt | 1 + libs/utils/gtest/CMakeLists.txt | 1 + libs/utils/gtest/src/ErrTestSuite.cc | 56 ++++++++++++++++ libs/utils/include/celix_err.h | 71 ++++++++++++++++++++ libs/utils/src/celix_err.c | 124 +++++++++++++++++++++++++++++++++++ 5 files changed, 253 insertions(+) diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt index db500513..d57c0c7c 100644 --- a/libs/utils/CMakeLists.txt +++ b/libs/utils/CMakeLists.txt @@ -44,6 +44,7 @@ add_library(utils_obj OBJECT src/celix_hash_map.c src/celix_file_utils.c src/celix_convert_utils.c + src/celix_err.c ${MEMSTREAM_SOURCES} ) diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt index 2d8a47f5..47e92d96 100644 --- a/libs/utils/gtest/CMakeLists.txt +++ b/libs/utils/gtest/CMakeLists.txt @@ -33,6 +33,7 @@ add_executable(test_utils src/FilterTestSuite.cc src/CelixUtilsTestSuite.cc src/ConvertUtilsTestSuite.cc + src/ErrTestSuite.cc ${CELIX_UTIL_TEST_SOURCES_FOR_CXX_HEADERS} ) diff --git a/libs/utils/gtest/src/ErrTestSuite.cc b/libs/utils/gtest/src/ErrTestSuite.cc new file mode 100644 index 00000000..abb15cb6 --- /dev/null +++ b/libs/utils/gtest/src/ErrTestSuite.cc @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#include <gtest/gtest.h> + +#include "celix_err.h" + +class ErrTestSuite : public ::testing::Test { +public: + ErrTestSuite() = default; + ~ErrTestSuite() noexcept override = default; +}; + +TEST_F(ErrTestSuite, AddAndPopErrorTest) { + EXPECT_EQ(0, celix_err_getErrorCount()); + celix_err_push("error message"); + celix_err_pushf("error message from %s", "test"); + EXPECT_EQ(2, celix_err_getErrorCount()); + + auto* m = celix_err_popLastError(); + EXPECT_STREQ("error message from test", m); + free(m); + EXPECT_EQ(1, celix_err_getErrorCount()); + + m = celix_err_popLastError(); + EXPECT_STREQ("error message", m); + free(m); + EXPECT_EQ(0, celix_err_getErrorCount()); +} + +TEST_F(ErrTestSuite, ResetErrorTest) { + EXPECT_EQ(0, celix_err_getErrorCount()); + celix_err_push("error message"); + celix_err_push("error message"); + EXPECT_EQ(2, celix_err_getErrorCount()); + + celix_err_resetErrors(); + EXPECT_EQ(0, celix_err_getErrorCount()); + EXPECT_EQ(nullptr, celix_err_popLastError()); +} diff --git a/libs/utils/include/celix_err.h b/libs/utils/include/celix_err.h new file mode 100644 index 00000000..16bd2d31 --- /dev/null +++ b/libs/utils/include/celix_err.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#ifndef CELIX_CELIX_ERR_H +#define CELIX_CELIX_ERR_H + +#include "celix_utils_export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @file celix_err.h +* @brief The celix error handling functions. +* @thread_safety Thread safe. +*/ + +/** + * @brief Returns the last error message from the current thread. + * The error message must be freed by the caller. + * @returnval NULL if no error message is available. + */ +CELIX_UTILS_EXPORT +char* celix_err_popLastError(); //TODO update to return const char* and remove free + +/** + * @brief Push an formatted error message to the thread specific storage rcm errors. + */ +CELIX_UTILS_EXPORT +void celix_err_pushf(const char* format, ...) __attribute__((format(printf, 1, 2))); + +/** + * @brief Push an error message to the thread specific storage rcm errors. + */ +CELIX_UTILS_EXPORT +void celix_err_push(const char* msg); + +/** + * @brief Returns the number of error messages from the current thread. + */ +CELIX_UTILS_EXPORT +int celix_err_getErrorCount(); + +/** + * @brief Resets the error message for the current thread. + */ +CELIX_UTILS_EXPORT +void celix_err_resetErrors(); + +#ifdef __cplusplus +} +#endif + +#endif //CELIX_CELIX_ERR_H diff --git a/libs/utils/src/celix_err.c b/libs/utils/src/celix_err.c new file mode 100644 index 00000000..939c7078 --- /dev/null +++ b/libs/utils/src/celix_err.c @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#include "celix_err.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <pthread.h> + +#include "celix_array_list.h" +#include "celix_utils.h" + +pthread_key_t celix_rcm_tssErrorsKey; //TODO replace with celix_tss_key and celix_tss_* functions + +static void celix_err_destroyTssErrors(void* data) { + //TODO replace array list with some thread specific storage char buffer + celix_array_list_t* errors = data; + if (errors != NULL) { + for (int i = 0; i < celix_arrayList_size(errors); ++i) { + char* msg = celix_arrayList_get(errors, i); + free(msg); + } + } + celix_arrayList_destroy(errors); +} + +__attribute__((constructor)) void celix_err_initThreadSpecificStorageKey() { + int rc = pthread_key_create(&celix_rcm_tssErrorsKey, celix_err_destroyTssErrors); + if (rc != 0) { + fprintf(stderr,"Failed to create thread specific storage key for celix_err\n"); + } +} + +__attribute__((destructor)) void celix_err_deinitThreadSpecificStorageKey() { + int rc = pthread_key_delete(celix_rcm_tssErrorsKey); + if (rc != 0) { + fprintf(stderr,"Failed to delete thread specific storage key for celix_err\n"); + } +} + +char* celix_err_popLastError() { + char* result = NULL; + celix_array_list_t* errors = pthread_getspecific(celix_rcm_tssErrorsKey); + if (errors != NULL && celix_arrayList_size(errors) > 0) { + int last = celix_arrayList_size(errors) - 1; + result = celix_arrayList_get(errors, last); + celix_arrayList_removeAt(errors, last); + } + return result; +} + +int celix_err_getErrorCount() { + int result = 0; + celix_array_list_t* errors = pthread_getspecific(celix_rcm_tssErrorsKey); + if (errors != NULL) { + result = celix_arrayList_size(errors); + } + return result; +} + +void celix_err_resetErrors() { + celix_array_list_t* errors = pthread_getspecific(celix_rcm_tssErrorsKey); + celix_err_destroyTssErrors(errors); + pthread_setspecific(celix_rcm_tssErrorsKey, NULL); +} + +static void celix_err_pushMsg(char* msg) { + celix_array_list_t* errors = pthread_getspecific(celix_rcm_tssErrorsKey); + if (errors == NULL) { + errors = celix_arrayList_create(); + if (errors == NULL) { + fprintf(stderr, "Failed to create error list for Apache Celix rcm lib\n"); + free(msg); + return; + } + pthread_setspecific(celix_rcm_tssErrorsKey, errors); + } + if (errors != NULL) { + celix_status_t rc = celix_arrayList_add(errors, msg); + if (rc != CELIX_SUCCESS) { + fprintf(stderr, "Failed to add error to error list for Apache Celix rcm lib\n"); + free(msg); + } + } +} + +void celix_err_push(const char* msg) { + char* msgCpy = celix_utils_strdup(msg); + if (msgCpy == NULL) { + fprintf(stderr, "Failed to copy error message for Apache Celix rcm lib\n"); + return; + } + celix_err_pushMsg(msgCpy); +} + +void celix_err_pushf(const char* format, ...) { + va_list args; + va_start(args, format); + char* msg = NULL; + int rc = vasprintf(&msg, format, args); + if (rc >= 0) { + celix_err_pushMsg(msg); + } else { + fprintf(stderr, "Failed to copy error message for Apache Celix rcm lib\n"); + } + va_end(args); +}
