* 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) {
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);
}
*/
#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;
};
+++ /dev/null
-/*
- * 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);
-
#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);
}
--- /dev/null
+/*
+ * 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);
* @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
*/
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.
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)
{
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);
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);
}