introduce a refcounter for data 49/26849/2
authorJozef Kralik <jozef.kralik@kistler.com>
Thu, 30 Aug 2018 07:23:57 +0000 (09:23 +0200)
committerJozef Kralik <jozef.kralik@kistler.com>
Thu, 6 Sep 2018 10:29:29 +0000 (12:29 +0200)
- provides interface and implementation of reference counter
- for example of using look to:
  resource/c_common/oc_refcounter/test/linux/oc_refcounter_tests.cpp

Bug: https://jira.iotivity.org/browse/IOT-3075
Bug: https://jira.iotivity.org/browse/IOT-3059
Change-Id: Ib4f04677cdc6951a0a9505efbd6ab47a7a79288b
Signed-off-by: Jozef Kralik <jozef.kralik@kistler.com>
resource/c_common/SConscript
resource/c_common/oc_refcounter/include/oc_refcounter.h [new file with mode: 0644]
resource/c_common/oc_refcounter/src/oc_refcounter.c [new file with mode: 0644]
resource/c_common/oc_refcounter/test/SConscript [new file with mode: 0644]
resource/c_common/oc_refcounter/test/linux/oc_refcounter_tests.cpp [new file with mode: 0644]
resource/c_common/unittests/SConscript
resource/docs/c-doc/devdocs.doxyfile

index b84d2ec..e7cf0e2 100644 (file)
@@ -149,6 +149,7 @@ env.AppendUnique(CPPPATH=[
     os.path.join(Dir('.').abspath, 'ocevent', 'include'),
     os.path.join(Dir('.').abspath, 'oic_platform', 'include'),
     os.path.join(Dir('.').abspath, 'octimer', 'include'),
+    os.path.join(Dir('.').abspath, 'oc_refcounter', 'include'),
     '#/extlibs/mbedtls/mbedtls/include'
 ])
 
@@ -176,7 +177,8 @@ common_src = [
     'oic_malloc/src/oic_malloc.c',
     'oic_time/src/oic_time.c',
     'ocrandom/src/ocrandom.c',
-    'oic_platform/src/oic_platform.c'
+    'oic_platform/src/oic_platform.c',
+    'oc_refcounter/src/oc_refcounter.c'
 ]
 
 if env['POSIX_SUPPORTED']:
diff --git a/resource/c_common/oc_refcounter/include/oc_refcounter.h b/resource/c_common/oc_refcounter/include/oc_refcounter.h
new file mode 100644 (file)
index 0000000..ff5c274
--- /dev/null
@@ -0,0 +1,90 @@
+/******************************************************************
+ *
+ * Copyright 2018 Kistler Group All Rights Reserved.
+ *
+ *
+ *
+ * Licensed 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 OC_REFCOUNTER_H_
+#define OC_REFCOUNTER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+typedef struct oc_refcounter_t *oc_refcounter;
+
+/**
+ * Desctructor of a data of a refcounter and it is called when a counter of thet refcounter reach 0.
+ */
+typedef void (*oc_refcounter_dtor_data_func)(void* data);
+
+/**
+ * Creates a new refcounter of a data. Ownership of the data is transferred to the refcounter.
+ * For deallocates the data use oc_refcounter_dec, otherwise it can cause crash of the application.
+ *
+ * @param data - Data which will be owned by refcounter
+ * @param dtor - Destructor of a data
+ *
+ * @return Poiner to newly created refcounter, NULL on allocation failure.
+ */
+oc_refcounter oc_refcounter_create(void* data, oc_refcounter_dtor_data_func dtor);
+
+/**
+ * Increments atommically reference count of a refcounter
+ *
+ * @param ref - A pointer to the refcounter
+ *
+ * @return returns the ref
+ */
+oc_refcounter oc_refcounter_inc(oc_refcounter ref);
+
+/**
+ * Decrements atommically a reference count of a refcounter. If the count of the refcounter
+ * reach 0, it's call destructor of a data and the refcounter.
+ *
+ * @param ref - A pointer to the refcounter
+ *
+ * @return
+ *     on count == 0, a null pointer is returned
+ *     otherwise returns the refcounter
+ */
+oc_refcounter oc_refcounter_dec(oc_refcounter ref);
+
+/**
+ * Gets a current reference count of the refcount
+ *
+ * @param ref -  A pointer to the refcounter
+ *
+ * @return returns a current reference count of the block
+ */
+int32_t oc_refcounter_get_count(oc_refcounter ref);
+
+/**
+ * Gets a data of the refcount
+ *
+ * @param ref -  A pointer to the refcounter
+ *
+ * @return returns a data of the refcounter
+ */
+void* oc_refcounter_get_data(oc_refcounter ref);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+#endif // OC_REFCOUNTER_H_
diff --git a/resource/c_common/oc_refcounter/src/oc_refcounter.c b/resource/c_common/oc_refcounter/src/oc_refcounter.c
new file mode 100644 (file)
index 0000000..7e6566f
--- /dev/null
@@ -0,0 +1,116 @@
+/******************************************************************
+ *
+ * Copyright 2018 Kistler Group All Rights Reserved.
+ *
+ *
+ *
+ * Licensed 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 "oc_refcounter.h"
+
+#include "oic_malloc.h"
+#include "ocatomic.h"
+#include "iotivity_debug.h"
+
+// Enable extra debug logging for malloc.  Comment out to disable
+#ifdef ENABLE_REFCOUNTER_DEBUG
+#include "experimental/logger.h"
+#define TAG "OC_REFCOUNT"
+#endif
+
+typedef struct oc_refcounter_t
+{
+    /* count of the references*/
+    int32_t                      count;
+    /* data owned by refcount */
+    void*                        data;
+    /* data destructor*/
+    oc_refcounter_dtor_data_func dtor;
+} oc_refcounter_t;
+
+oc_refcounter oc_refcounter_create(void* data, oc_refcounter_dtor_data_func dtor)
+{
+    oc_refcounter ref = (oc_refcounter)OICMalloc(sizeof(*ref));
+    if (ref == NULL)
+    {
+        return ref;
+    }
+    ref->count = 1;
+#ifdef ENABLE_REFCOUNTER_DEBUG
+    OIC_LOG_V(INFO, TAG, "oc_refcounter_create: ref=%p count=%d", ref, 1);
+#endif
+    ref->data = data;
+    ref->dtor = dtor;
+
+    return ref;
+}
+
+oc_refcounter oc_refcounter_inc(oc_refcounter ref)
+{
+    if (ref == NULL)
+    {
+        return NULL;
+    }
+    OC_VERIFY(ref->count > 0);
+    int32_t count = oc_atomic_increment(&ref->count);
+#ifdef ENABLE_REFCOUNTER_DEBUG
+    OIC_LOG_V(INFO, TAG, "oc_refcounter_inc: ref=%p count=%d", ref, count);
+#else
+    (void) count;
+#endif
+    return ref;
+}
+
+oc_refcounter oc_refcounter_dec(oc_refcounter ref)
+{
+    if (ref == NULL)
+    {
+        return NULL;
+    }
+    OC_VERIFY(ref->count > 0);
+    int32_t count = oc_atomic_decrement(&ref->count);
+#ifdef ENABLE_REFCOUNTER_DEBUG
+    OIC_LOG_V(INFO, TAG, "oc_refcounter_dec: ref=%p count=%d", ref, count);
+#endif
+    if (count == 0)
+    {
+        if (ref->dtor)
+        {
+            ref->dtor(ref->data);
+        }
+        OICFree(ref);
+        return NULL;
+    }
+    return ref;
+}
+
+int32_t oc_refcounter_get_count(oc_refcounter ref)
+{
+    if (ref == NULL)
+    {
+        return -1;
+    }
+    OC_VERIFY(ref->count > 0);
+    return ref->count;
+}
+
+void* oc_refcounter_get_data(oc_refcounter ref)
+{
+    if (ref == NULL)
+    {
+        return NULL;
+    }
+    OC_VERIFY(ref->count > 0);
+    return ref->data;
+}
\ No newline at end of file
diff --git a/resource/c_common/oc_refcounter/test/SConscript b/resource/c_common/oc_refcounter/test/SConscript
new file mode 100644 (file)
index 0000000..130c5f0
--- /dev/null
@@ -0,0 +1,56 @@
+#******************************************************************
+#
+# Copyright 2018 Kistler Group All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed 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.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+import os
+import os.path
+from tools.scons.RunTest import run_test
+
+Import('test_env')
+
+# SConscript file for Local PKI google tests
+refcountertest_env = test_env.Clone()
+target_os = refcountertest_env.get('TARGET_OS')
+
+######################################################################
+# Build flags
+######################################################################
+refcountertest_env.PrependUnique(CPPPATH=['../include'])
+
+refcountertest_env.AppendUnique(LIBPATH=[
+    os.path.join(refcountertest_env.get('BUILD_DIR'), 'resource', 'c_common')
+])
+refcountertest_env.PrependUnique(LIBS=['c_common'])
+
+if refcountertest_env.get('LOGGING'):
+    refcountertest_env.AppendUnique(CPPDEFINES=['TB_LOG'])
+#
+######################################################################
+# Source files and Targets
+######################################################################
+refcountertests = refcountertest_env.Program('refcountertests',
+                                     ['linux/oc_refcounter_tests.cpp'])
+
+Alias("test", [refcountertests])
+
+refcountertest_env.AppendTarget('test')
+if refcountertest_env.get('TEST') == '1':
+    if target_os in ['linux', 'windows']:
+        run_test(refcountertest_env, 'resource_ccommon_refcounter_test.memcheck',
+                 'resource/c_common/oc_refcounter/test/refcountertests')
diff --git a/resource/c_common/oc_refcounter/test/linux/oc_refcounter_tests.cpp b/resource/c_common/oc_refcounter/test/linux/oc_refcounter_tests.cpp
new file mode 100644 (file)
index 0000000..26eff35
--- /dev/null
@@ -0,0 +1,72 @@
+//******************************************************************
+//
+// Copyright 2018 Kistler Group All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed 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 "iotivity_config.h"
+
+extern "C" {
+    #include "oc_refcounter.h"
+}
+
+#include <gtest/gtest.h>
+
+//-----------------------------------------------------------------------------
+// Includes
+//-----------------------------------------------------------------------------
+
+#include <stdint.h>
+using namespace std;
+
+//-----------------------------------------------------------------------------
+//  Tests
+//-----------------------------------------------------------------------------
+
+TEST(RefCounterTests, OCRefCounterCreateNormalNonDtor)
+{
+    oc_refcounter result = oc_refcounter_create(NULL, NULL);
+    EXPECT_TRUE(result != NULL);
+
+    result = oc_refcounter_dec(result);
+    EXPECT_TRUE(result == NULL);
+}
+
+static void dtorVal(int* v)
+{
+    *v = 0;
+}
+
+TEST(RefCounterTests, OCRefCounterIncDecWithDtor)
+{
+    int val = 1;
+    oc_refcounter result = oc_refcounter_create(&val, (oc_refcounter_dtor_data_func) dtorVal);
+    EXPECT_TRUE(result != NULL);
+    EXPECT_EQ(1, oc_refcounter_get_count(result));
+
+    result = oc_refcounter_inc(result);
+    EXPECT_TRUE(result != NULL);
+    EXPECT_EQ(2, oc_refcounter_get_count(result));
+
+    result = oc_refcounter_dec(result);
+    EXPECT_TRUE(result != NULL);
+    EXPECT_EQ(1, oc_refcounter_get_count(result));
+
+    result = oc_refcounter_dec(result);
+    EXPECT_TRUE(result == NULL);
+    EXPECT_EQ(0, val);
+}
\ No newline at end of file
index 6f9d79e..ef1bbf4 100644 (file)
@@ -38,6 +38,7 @@ SConscript(exports={'test_env': common_test_env},
                '../oic_time/test',
                '../ocrandom/test',
                '../ocevent/test',
+               '../oc_refcounter/test',
            ])
 if target_os == 'windows':
     SConscript('../windows/test/SConscript', exports={'test_env': common_test_env})
index b72bea7..68fa944 100644 (file)
@@ -135,7 +135,9 @@ INPUT                  = devdox \
                          ../../c_common/windows/include \
                          ../../c_common/windows/src \
                          ../../c_common/ocrandom/include \
-                         ../../c_common/ocrandom/src
+                         ../../c_common/ocrandom/src \
+                         ../../c_common/oc_refcounter/include \
+                         ../../c_common/oc_refcounter/src
 
 INPUT_ENCODING         = UTF-8
 FILE_PATTERNS          =