revise subscribe changes functions with ID
authorYoungjae Shin <yj99.shin@samsung.com>
Mon, 16 Mar 2020 10:55:36 +0000 (19:55 +0900)
committerYoungjae Shin <yj99.shin@samsung.com>
Wed, 18 Mar 2020 08:53:50 +0000 (17:53 +0900)
client/mdsc.c
client/mdsc.h
client/mdsc_dbus.h [deleted file]
client/mdsc_noti_mode.c
client/mdsc_noti_mode.h [new file with mode: 0644]
include/modes.h
include/modes_types.h
unittest/modes_test_noti.cpp

index 8d5d85769b0b431d4e9ace1e0158fa6c244c93e2..fba12f83b38dd76d651626eac1476c1bb766de02 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "modes.h"
 
 #include <stdlib.h>
 #include <glib.h>
 #include "mdsc.h"
 #include "common/dbus.h"
 #include "common/dbus_def.h"
+#include "mdsc_noti_mode.h"
 
 API modes_h modes_connect()
 {
-       modes_h handle = malloc(sizeof(struct mds_handle));
-       RETV_IF(NULL == handle, NULL);
-
        mdsDbus *proxy;
        GError *gdbusErr = NULL;
+
+       modes_h handle = calloc(1, sizeof(struct mds_handle));
+       if (NULL == handle) {
+               ERR("calloc() Fail(%d)", errno);
+               return NULL;
+       }
+
+       if (pthread_mutex_init(&handle->noti_mutex, NULL)) {
+               ERR("pthread_mutex_init() Fail(%d)", errno);
+               free(handle);
+               return NULL;
+       }
+
        proxy = mds_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
                        G_DBUS_PROXY_FLAGS_NONE, MODES_DBUS_INTERFACE, MODES_DBUS_OBJPATH, NULL, &gdbusErr);
        if (NULL == proxy) {
@@ -43,9 +55,11 @@ API modes_h modes_connect()
 API void modes_disconnect(modes_h handle)
 {
        RET_IF(NULL == handle);
-       if (handle->conn) {
-               g_object_unref(handle->conn);
-               handle->conn = NULL;
-       }
+
+       mdsc_noti_terminate(handle);
+       pthread_mutex_destroy(&handle->noti_mutex);
+       g_object_unref(handle->conn);
+       handle->conn = NULL;
+
        free(handle);
 }
index a8ef234f29ec517731dc131923469af916f7010b..76d27b7d1f22638a6295e9199f62794b61f0ffcf 100644 (file)
  */
 #pragma once
 
-#include "modes.h"
-#include "common/dbus.h"
+#include <pthread.h>
 #include "common/log.h"
+#include "common/dbus.h"
 #include "common/definitions.h"
 
 struct mds_handle {
        mdsDbus *conn;
+       gulong noti_dbus_ID;
+       GList *noti_cb_list;
+       pthread_mutex_t noti_mutex;
 };
diff --git a/client/mdsc_dbus.h b/client/mdsc_dbus.h
deleted file mode 100644 (file)
index 1660fd3..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2019-2020 Samsung Electronics Co., Ltd 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.
- */
-#pragma once
-
-#include "common/dbus.h"
-
-mdsDbus* mdsc_dbus_start();
-void mdsc_dbus_stop(mdsDbus *handle);
-
index 87c58a7543f0c18d061d74455bde7ab3bda2cdab..368e86328d87c9339948b876446e369573915047 100644 (file)
 #include "mdsc.h"
 #include "common/dbus.h"
 
-typedef struct {
+struct mds_noti_data {
        modes_noti_fn cb;
        void *user_data;
-} mdsc_noti_data_s;
+};
 
-static gulong mdsc_noti_signal_ID = 0;
-static GList *mdsc_noti_cb_list = NULL;
+static void _mutex_lock(pthread_mutex_t *mutex)
+{
+       int ret = pthread_mutex_lock(mutex);
+       if (0 != ret)
+               ERR("pthread_mutex_lock() Fail(%d)", errno);
+}
 
-static gint _compare_cb(gconstpointer a, gconstpointer b)
+static void _mutex_unlock(pthread_mutex_t *mutex)
 {
-       RETV_IF(NULL == a, 1);
-       RETV_IF(NULL == b, 1);
-
-       const mdsc_noti_data_s *a_data = a;
-       const mdsc_noti_data_s *b_data = b;
-       if ((a_data->cb == b_data->cb)
-               && (a_data->user_data == b_data->user_data))
-               return 0;
-       return -1;
+       int ret = pthread_mutex_lock(mutex);
+       if (0 != ret)
+               ERR("pthread_mutex_lock() Fail(%d)", errno);
 }
 
 static void _on_changed_mode(mdsDbus *mdsc_dbus, const char *mode, int state, gpointer user_data)
 {
+       int i;
        GList *it;
-       for (it = mdsc_noti_cb_list; it != NULL; it = g_list_next(it)) {
-               mdsc_noti_data_s *data = it->data;
-               if (data && data->cb)
-                       data->cb(mode, state, data->user_data);
+       modes_h handle = user_data;
+
+       RET_IF(NULL == handle);
+
+       _mutex_lock(&handle->noti_mutex);
+       int length = g_list_length(handle->noti_cb_list);
+       struct mds_noti_data cb_list[length];
+
+       for (i = 0, it = handle->noti_cb_list; it != NULL; it = g_list_next(it), i++) {
+               modes_noti_ID data = it->data;
+               if (data) {
+                       cb_list[i].cb = data->cb;
+                       cb_list[i].user_data = data->user_data;
+               }
+       }
+       _mutex_unlock(&handle->noti_mutex);
+
+       for (; 0 <= i; i--) {
+               if (cb_list[i].cb)
+                       cb_list[i].cb(mode, state, cb_list[i].user_data);
        }
 }
 
-API int modes_subscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data)
+API modes_noti_ID modes_subscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data)
 {
-       RETV_IF(NULL == handle, MODES_ERROR_INVALID_PARAMETER);
-       RETV_IF(NULL == handle->conn, MODES_ERROR_INVALID_PARAMETER);
-
-       mdsc_noti_data_s search_data = { cb, user_data };
-       GList *found = g_list_find_custom(mdsc_noti_cb_list, &search_data, _compare_cb);
-       if (NULL != found) {
-               ERR("callback and user_data already exist in notification callback list");
-               return MODES_ERROR_ALREADY;
-       }
+       RETV_IF(NULL == handle, NULL);
+       RETV_IF(NULL == handle->conn, NULL);
 
-       mdsc_noti_data_s *data = malloc(sizeof(mdsc_noti_data_s));
+       modes_noti_ID data = malloc(sizeof(struct mds_noti_data));
        if (NULL == data) {
-               ERR("malloc() Fail");
-               return MODES_ERROR_SYSTEM;
+               ERR("malloc() Fail(%d)", errno);
+               return NULL;
        }
 
        data->cb = cb;
        data->user_data = user_data;
 
-       if (NULL == mdsc_noti_cb_list)
-               mdsc_noti_signal_ID = g_signal_connect(handle->conn,
+       if (NULL == handle->noti_cb_list)
+               handle->noti_dbus_ID = g_signal_connect(handle->conn,
                        "changed-mode",
                        G_CALLBACK(_on_changed_mode),
-                       NULL);
-       mdsc_noti_cb_list = g_list_append(mdsc_noti_cb_list, data);
+                       handle);
+
+       _mutex_lock(&handle->noti_mutex);
+       handle->noti_cb_list = g_list_append(handle->noti_cb_list, data);
+       _mutex_unlock(&handle->noti_mutex);
 
-       return MODES_ERROR_NONE;
+       return data;
 }
 
-API void modes_unsubscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data)
+API void modes_unsubscribe_mode_changes(modes_h handle, modes_noti_ID id)
 {
-       RET_IF(0 == mdsc_noti_signal_ID);
        RET_IF(NULL == handle);
        RET_IF(NULL == handle->conn);
 
-       mdsc_noti_data_s search = { cb, user_data };
-       GList *found = g_list_find_custom(mdsc_noti_cb_list, &search, _compare_cb);
-       if (NULL == found) {
-               WARN("g_list_find_custom() Fail");
-               return;
+       _mutex_lock(&handle->noti_mutex);
+       handle->noti_cb_list = g_list_remove(handle->noti_cb_list, id);
+       free(id);
+       if (NULL == handle->noti_cb_list) {
+               g_signal_handler_disconnect(handle->conn, handle->noti_dbus_ID);
+               handle->noti_dbus_ID = 0;
        }
+       _mutex_unlock(&handle->noti_mutex);
+}
 
-       mdsc_noti_data_s *data = found->data;
-       mdsc_noti_cb_list = g_list_remove(mdsc_noti_cb_list, found->data);
-       free(data);
-       if (NULL == mdsc_noti_cb_list) {
-               g_signal_handler_disconnect(handle->conn, mdsc_noti_signal_ID);
-               mdsc_noti_signal_ID = 0;
-       }
+void mdsc_noti_terminate(modes_h handle)
+{
+       RET_IF(NULL == handle);
 
+       _mutex_lock(&handle->noti_mutex);
+       if (handle->noti_cb_list) {
+               g_list_free_full(handle->noti_cb_list, free);
+               handle->noti_cb_list = NULL;
+               g_signal_handler_disconnect(handle->conn, handle->noti_dbus_ID);
+               handle->noti_dbus_ID = 0;
+       }
+       _mutex_unlock(&handle->noti_mutex);
 }
diff --git a/client/mdsc_noti_mode.h b/client/mdsc_noti_mode.h
new file mode 100644 (file)
index 0000000..6e53cbf
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019-2020 Samsung Electronics Co., Ltd 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.
+ */
+#pragma once
+
+#include "modes.h"
+
+void mdsc_noti_terminate(modes_h handle);
index a994552e51d6848d589ff91797b72cafb465154f..d93675a60307a2f6364a7dccd014d5f92a3a2377 100644 (file)
@@ -235,27 +235,23 @@ typedef int (*modes_noti_fn) (const char *mode_name, int state, void *user_data)
  * @param[in] cb The callback function to invoke
  * @param[in] user_data The user data to pass to the function
  *
- * @return 0 on success, otherwise a negative error value.
- * @retval #MODES_ERROR_NONE Successful
- * @retval #MODES_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #MODES_ERROR_SYSTEM System errors
+ * @return The ID (greater than 0), otherwise NULL(0).
  *
  * @see modes_unsubscribe_mode_changes()
  */
-int modes_subscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data);
+modes_noti_ID modes_subscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data);
 
 /**
  * @brief stop recognizing the changed of mode.
- * @details Removes a function to be called when the mode is changed.
+ * @details Removes the subscription of changes with given ID.
  * @since_tizen 6.0
  *
- * @param[in] Handle of modes server
- * @param[in] cb The callback function to stop invoking
- * @param[in] user_data The user data to pass to the function
+ * @param[in] handle Handle of modes API
+ * @param[in] id The ID of the subscription of changes
  *
  * @see modes_subscribe_mode_changes()
  */
-void modes_unsubscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data);
+void modes_unsubscribe_mode_changes(modes_h handle, modes_noti_ID id);
 
 /**
  * @brief Get mode list
index 48ef08416bd684760b702811e7b97772312625d8..06e4355311144f7f30a18b8dbfa244c07e3fdb4d 100644 (file)
  */
 typedef struct mds_handle* modes_h;
 
+/**
+ * @brief The Modes notification ID.
+ * @details @a modes_noti_ID is an opaque data structure to represent modes notification ID.
+ * @since_tizen 6.0
+ */
+typedef struct mds_noti_data* modes_noti_ID;
+
 /**
  * @brief The Modes mode handle.
  * @details @a modes_mode_h is an opaque data structure to represent mode data.
index fb7f738854e89bfa8c304d6c8c268e4098ef0b7e..183bb785e75af124fdb4a8964d9d3857c6d00b4d 100644 (file)
@@ -131,18 +131,18 @@ const char *ClientNotiTest::notiTestMode = "ex2";
 TEST_F(ClientNotiTest, notiConnect)
 {
        const char *testMode = "ex2";
-       int ret = modes_subscribe_mode_changes(handle, notiFunc, (void*)testMode);
-       EXPECT_EQ(MODES_ERROR_NONE, ret);
+       modes_noti_ID id = modes_subscribe_mode_changes(handle, notiFunc, (void*)testMode);
+       EXPECT_NE(nullptr , id);
 
        ClientNotiTest::expectedState = 1;
-       ret = modes_apply_mode(handle, testMode);
+       int ret = modes_apply_mode(handle, testMode);
        EXPECT_EQ(MODES_ERROR_NONE, ret);
 
        g_timeout_add_seconds(1, undoTimeout, (void*)testMode);
 
        g_main_loop_run(loop);
 
-       modes_unsubscribe_mode_changes(handle, notiFunc, (void*)testMode);
+       modes_unsubscribe_mode_changes(handle, id);
 }
 TEST_F(ClientNotiTest, notiMultiCb)
 {
@@ -150,28 +150,28 @@ TEST_F(ClientNotiTest, notiMultiCb)
        calledbit2 = 0;
        calledbit3 = 0;
 
-       int ret = modes_subscribe_mode_changes(handle, notiMultiFunc1, NULL);
-       EXPECT_EQ(MODES_ERROR_NONE, ret);
+       modes_noti_ID id1 = modes_subscribe_mode_changes(handle, notiMultiFunc1, NULL);
+       EXPECT_NE(nullptr, id1);
 
-       ret = modes_subscribe_mode_changes(handle, notiMultiFunc2, NULL);
-       EXPECT_EQ(MODES_ERROR_NONE, ret);
+       modes_noti_ID id2 = modes_subscribe_mode_changes(handle, notiMultiFunc2, NULL);
+       EXPECT_NE(nullptr, id2);
 
-       ret = modes_subscribe_mode_changes(handle, notiMultiFunc3, (void*)notiTestMode);
-       EXPECT_EQ(MODES_ERROR_NONE, ret);
+       modes_noti_ID id3 = modes_subscribe_mode_changes(handle, notiMultiFunc3, (void*)notiTestMode);
+       EXPECT_NE(nullptr, id3);
 
-       ret = modes_subscribe_mode_changes(handle, notiMultiFunc3, NULL);
-       EXPECT_EQ(MODES_ERROR_NONE, ret);
+       modes_noti_ID id4 = modes_subscribe_mode_changes(handle, notiMultiFunc3, NULL);
+       EXPECT_NE(nullptr, id4);
 
-       ret = modes_apply_mode(handle, notiTestMode);
+       int ret = modes_apply_mode(handle, notiTestMode);
        EXPECT_EQ(MODES_ERROR_NONE, ret);
 
        g_timeout_add_seconds(1, undoTimeout, (void*)notiTestMode);
        g_main_loop_run(loop);
 
-       modes_unsubscribe_mode_changes(handle, notiMultiFunc1, NULL);
-       modes_unsubscribe_mode_changes(handle, notiMultiFunc2, NULL);
-       modes_unsubscribe_mode_changes(handle, notiMultiFunc3, NULL);
-       modes_unsubscribe_mode_changes(handle, notiMultiFunc3, (void*)notiTestMode);
+       modes_unsubscribe_mode_changes(handle, id1);
+       modes_unsubscribe_mode_changes(handle, id2);
+       modes_unsubscribe_mode_changes(handle, id3);
+       modes_unsubscribe_mode_changes(handle, id4);
 
        EXPECT_EQ(calledbit1, 1 << 0 | 1 << 1);
        EXPECT_EQ(calledbit2, 1 << 0 | 1 << 1);
@@ -182,13 +182,13 @@ TEST_F(ClientNotiTest, notiMultiCb)
 TEST_F(ClientNotiTest, essential)
 {
        const char *testMode = "essential_ex";
-       int ret = modes_subscribe_mode_changes(handle, changeFn, (void*)testMode);
-       EXPECT_EQ(MODES_ERROR_NONE, ret);
+       modes_noti_ID id = modes_subscribe_mode_changes(handle, changeFn, (void*)testMode);
+       EXPECT_NE(nullptr, id);
 
-       ret = modes_apply_mode(handle, testMode);
+       int ret = modes_apply_mode(handle, testMode);
        EXPECT_EQ(MODES_ERROR_NONE, ret);
 
        g_main_loop_run(loop);
 
-       modes_unsubscribe_mode_changes(handle, changeFn, (void*)testMode);
+       modes_unsubscribe_mode_changes(handle, id);
 }