client: Support user data for AMB_PROPERTY_CHANGED_CALLBACK 34/93634/2
authorSangjung Woo <sangjung.woo@samsung.com>
Tue, 25 Oct 2016 04:59:47 +0000 (13:59 +0900)
committerSangjung Woo <sangjung.woo@samsung.com>
Wed, 26 Oct 2016 03:44:25 +0000 (12:44 +0900)
This patch supports the userdata for AMB_PROPERTY_CHANGED_CALLBACK
function when calling amb_register_property_changed_handler().

Change-Id: I30b7cd1cf6945dca40433dc0353455a4b1b73b2e
Signed-off-by: Sangjung Woo <sangjung.woo@samsung.com>
lib/client/libamb-client.c
lib/client/libamb-client.h
lib/client/libamb-common.h
lib/client/test/test.c

index 58cf8fd..6fa8a74 100644 (file)
 #define AMB_INTERFACE_NAME  "org.automotive.Manager"
 #define DBUS_INTERFACE_NAME "org.freedesktop.DBus.Properties"
 
+struct callback_item {
+       AMB_PROPERTY_CHANGED_CALLBACK callback;
+       void *user_data;
+       gboolean is_delete;
+       guint32 cid;
+};
+
 struct signal_item {
+       gchar *key;
        guint id;
        GDBusProxy *obj;
+       GList *cb_list;
+       guint32 next_cid;
 };
 
 /******************************************************************************
@@ -219,11 +229,13 @@ static void on_signal_handler(GDBusProxy *proxy,
                        gchar *sender_name,
                        gchar *signal_name,
                        GVariant *parameters,
-                       gpointer user_callback)
+                       gpointer signal_item)
 {
        gchar *obj_name;
        GVariant *value;
-       AMB_PROPERTY_CHANGED_CALLBACK callback = (AMB_PROPERTY_CHANGED_CALLBACK)user_callback;
+       GList *l;
+       GList *ll;
+       struct signal_item *item = (struct signal_item *)signal_item;
 
        if (g_strcmp0("PropertiesChanged", signal_name)) {
                DEBUGOUT("Error: signal name: %s\n", signal_name);
@@ -231,12 +243,44 @@ static void on_signal_handler(GDBusProxy *proxy,
        }
 
        g_variant_get(parameters, "(s@a{sv}as)", &obj_name, &value, NULL);
-       if (callback)
-               callback(obj_name, value);
 
+       for (l = item->cb_list; l != NULL; l = l->next) {
+               struct callback_item *citem = l->data;
+               if (!citem->is_delete && citem->callback) {
+                       citem->callback(obj_name, value, citem->user_data);
+               }
+       }
        g_free(obj_name);
        g_variant_unref(value);
 
+       // remove all marked callback items
+       for (l = item->cb_list, ll = g_list_next(l);
+               l != NULL;
+               l = ll, ll = g_list_next(ll)) {
+               struct callback_item *citem = l->data;
+               if (citem->is_delete) {
+                       DEBUGOUT("%s, id = %u is deleted\n", signal_name, citem->cid);
+                       g_free(citem);
+                       item->cb_list = g_list_delete_link(item->cb_list, l);
+               }
+       }
+
+       if (g_list_length(item->cb_list) == 0) {
+               DEBUGOUT("Remove item from htable\n");
+
+               GHashTable *htable = get_htable();
+               if (!htable) {
+                       DEBUGOUT("Error: get_htable() returns NULL\n");
+                       return ;
+               }
+
+               g_signal_handler_disconnect(item->obj, item->id);
+               if (!g_hash_table_remove(htable, item->key))
+                       DEBUGOUT("Error: fail to g_hash_table_remove()\n");
+
+               g_free(item->key);
+               g_free(item);
+       }
        return ;
 }
 
@@ -373,14 +417,19 @@ EXPORT void amb_release_property_all(GList *proplist)
 
 EXPORT int amb_register_property_changed_handler(gchar *objname,
                                ZoneType zone,
-                               AMB_PROPERTY_CHANGED_CALLBACK callback)
+                               AMB_PROPERTY_CHANGED_CALLBACK callback,
+                               void *user_data,
+                               guint32 *id)
 {
        GDBusProxy *proxy;
        GDBusProxy *objproxy;
-       guint id;
        struct signal_item *item;
+       struct callback_item *citem;
        GHashTable *htable;
 
+       if (callback == NULL)
+               return -EINVAL;
+
        htable = get_htable();
        if (!htable) {
                DEBUGOUT("Error: get_htable() returns NULL\n");
@@ -398,34 +447,53 @@ EXPORT int amb_register_property_changed_handler(gchar *objname,
                return -EINVAL;
        }
 
-       item = g_new0(struct signal_item, 1);
-       if (!item) {
+       if (!g_hash_table_lookup_extended(htable,
+                               g_dbus_proxy_get_object_path(objproxy),
+                               NULL, (gpointer*)&item)) {
+               guint sid;
+               DEBUGOUT("Not register: %s\n", g_dbus_proxy_get_object_path(objproxy));
+
+               item = g_new0(struct signal_item, 1);
+               if (!item) {
+                       DEBUGOUT("Error: fail to g_new0()\n");
+                       g_object_unref(objproxy);
+                       return -ENOMEM;
+               }
+               sid = g_signal_connect(objproxy, "g-signal", G_CALLBACK(on_signal_handler), (gpointer)item);
+
+               item->key = g_strdup(g_dbus_proxy_get_object_path(objproxy));
+               item->id = sid;
+               item->next_cid = 0;
+               item->obj = objproxy;
+               g_hash_table_insert(htable, item->key, item);
+       }
+
+       citem = g_new0(struct callback_item, 1);
+       if (!citem) {
                DEBUGOUT("Error: fail to g_new0()\n");
                g_object_unref(objproxy);
                return -ENOMEM;
        }
 
-       id = g_signal_connect(objproxy, "g-signal", G_CALLBACK(on_signal_handler), (gpointer)callback);
-       item->id = id;
-       item->obj = objproxy;
-
-       g_hash_table_insert(htable,
-                       g_strdup(g_dbus_proxy_get_object_path(objproxy)),
-                       item);
-
-       DEBUGOUT("instance: %s ID: %u\n", g_dbus_proxy_get_object_path(objproxy), id);
+       citem->cid = __atomic_fetch_add(&item->next_cid, 1, __ATOMIC_RELAXED);
+       citem->is_delete = FALSE;
+       citem->callback = callback;
+       citem->user_data = user_data;
+       *id = citem->cid;
+       item->cb_list = g_list_append(item->cb_list, citem);
 
+       DEBUGOUT("instance: %s ID: %u\n", g_dbus_proxy_get_object_path(objproxy), *id);
        return 0;
 }
 
-EXPORT int amb_unregister_property_changed_handler(gchar *objname, ZoneType zone)
+EXPORT int amb_unregister_property_changed_handler(gchar *objname, ZoneType zone, guint32 id)
 {
        GHashTable *htable;
        GDBusProxy *proxy;
        GDBusProxy *objproxy;
-       gpointer key;
        struct signal_item *item;
        gchar *objpath;
+       GList *l;
 
        htable = get_htable();
        if (!htable) {
@@ -446,22 +514,21 @@ EXPORT int amb_unregister_property_changed_handler(gchar *objname, ZoneType zone
 
        objpath = (gchar*)g_dbus_proxy_get_object_path(objproxy);
 
-       if (!g_hash_table_lookup_extended(htable, objpath, &key, (gpointer*)&item)) {
+       if (!g_hash_table_lookup_extended(htable, objpath, NULL, (gpointer*)&item)) {
                DEBUGOUT("Error: fail to find the object :%s\n", objpath);
                g_object_unref(objproxy);
                return -EINVAL;
        }
 
-       DEBUGOUT("instance: %s ID: %u\n", objpath, item->id);
-
-       g_signal_handler_disconnect(item->obj, item->id);
-       if (!g_hash_table_remove(htable, objpath)) {
-               DEBUGOUT("Error: fail to g_hash_table_remove()\n");
+       // mark to delete
+       for (l = item->cb_list; l != NULL; l = l->next) {
+               struct callback_item *citem = l->data;
+               if (citem->cid == id) {
+                       DEBUGOUT("%s: id: %u is marked to delete\n", objname, citem->cid);
+                       citem->is_delete = TRUE;
+               }
        }
-
-       g_free(key);
-       g_free(item);
-
+       DEBUGOUT("Delete monitoring: %s ID: %u\n", objpath, id);
        return 0;
 }
 
index 6f123c5..4e7624c 100644 (file)
@@ -49,10 +49,11 @@ typedef int ZoneType;
  *
  * @param[in] registered object name
  * @param[in] changed status
+ * @param[in] registered user data
  *
  * @see amb_unregister_property_changed_handler(), amb_unregister_property_changed_handler()
  */
-typedef void (*AMB_PROPERTY_CHANGED_CALLBACK)(const gchar *objname, gpointer data);
+typedef void (*AMB_PROPERTY_CHANGED_CALLBACK)(const gchar *objname, gpointer data, void *user_data);
 
 /**
  * primitive APIs
@@ -115,23 +116,28 @@ void amb_release_property_all_with_zone(GVariant *proplist);
  * @param[in] zone number to be set
  * @param[in] Callback function when the properties of monitored object
  * are changed.
+ * @param[in] User data for registered callback function
+ * @param[out] Registered ID to be used for unregister this handler
  * @return 0 on success, negative errno value on error
  *
  * @see amb_unregister_property_changed_handler(), AMB_PROPERTY_CHANGED_CALLBACK */
 int amb_register_property_changed_handler(gchar *objname,
                                        ZoneType zone,
-                                       AMB_PROPERTY_CHANGED_CALLBACK callback);
+                                       AMB_PROPERTY_CHANGED_CALLBACK callback,
+                                       void *user_data,
+                                       guint32 *id);
 
 /**
  * Unregister property changed handler.
  *
  * @param[in] Object name to be monitored
  * @param[in] zone number to be set
+ * @param[in] Registered ID
  * @return 0 on success, negative errno value on error
  *
  * @see amb_register_property_changed_handler(), AMB_PROPERTY_CHANGED_CALLBACK
  */
-int amb_unregister_property_changed_handler(gchar *objname, ZoneType zone);
+int amb_unregister_property_changed_handler(gchar *objname, ZoneType zone, guint32 id);
 
 /**
  * higher APIs
index 26616b2..ea7ffcd 100644 (file)
@@ -24,7 +24,7 @@
 #endif
 
 #if defined DEBUG
-#  define DEBUGOUT(fmt, ...) do { fprintf(stderr, fmt, __VA_ARGS__); } while(0);
+#  define DEBUGOUT(fmt, ...) do { fprintf(stderr, fmt, ##__VA_ARGS__); } while(0);
 #else
 #  define DEBUGOUT(fmt,...)
 #endif /* DEBUG */
index 2d8082e..b175b23 100644 (file)
@@ -1,4 +1,6 @@
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include <libamb-client.h>
 #include <libamb-objects.h>
@@ -98,91 +100,6 @@ static void test_set_property(const char *obj_name, const char *prop_name, int z
        amb_release_property_all_with_zone(ret);
 }
 
-static void signal_handler(const gchar *objname, gpointer data)
-{
-       gchar *s;
-       GVariant *gdata = (GVariant *)data;
-
-       if (!data)
-               return ;
-
-       s = g_variant_print(gdata, TRUE);
-       g_print("== signal_handler: %s\n", objname);
-       g_print("%s\n", s);
-
-       g_free(s);
-}
-
-static gboolean timer_callback(gpointer d)
-{
-       int rc;
-       gchar *objname = (gchar *)d;
-
-        fprintf(stderr, "Enter %s(): %s\n", __func__, objname);
-
-       rc = amb_unregister_property_changed_handler(objname, 0);
-       if (rc != 0) {
-                fprintf(stderr, "Fail to amb_unregister_property_changed_handler(): %s\n", objname);
-       }
-
-       return FALSE;
-}
-
-void test_signal_listen(gchar *objname, ZoneType zone)
-{
-       GMainLoop *loop;
-       int rc;
-
-       rc = amb_register_property_changed_handler(objname, zone, (AMB_PROPERTY_CHANGED_CALLBACK)signal_handler);
-       if (rc != 0) {
-                fprintf(stderr, "Fail to amb_register_property_changed_handler(): %s\n", objname);
-                return ;
-       }
-
-       g_timeout_add_seconds(10, timer_callback, objname);
-
-       loop = g_main_loop_new(NULL, FALSE);
-       g_main_loop_run(loop);
-
-       g_main_loop_unref(loop);
-}
-
-static void VehicleOdometer_handler(const gchar *objname, gpointer data)
-{
-       struct VehicleOdometerType retdata;
-
-       if (!data)
-               return ;
-
-       amb_convert_VehicleOdometerType(data, &retdata);
-
-       fprintf(stderr, " == VehicleOdometer ==\n");
-       fprintf(stderr, "    Zone: %d\n", retdata.Zone);
-       fprintf(stderr, "    Value: %d\n", retdata.Value);
-       fprintf(stderr, "    ValueSequence: %d\n", retdata.ValueSequence);
-       fprintf(stderr, "    Time: %f\n", retdata.Time);
-}
-
-static void test_VehicleOdometer_listen()
-{
-       GMainLoop *loop;
-       int rc;
-
-       rc = amb_register_property_changed_handler("VehicleOdometer", 0,
-                       (AMB_PROPERTY_CHANGED_CALLBACK)VehicleOdometer_handler);
-       if (rc != 0) {
-                fprintf(stderr, "Fail to amb_register_property_changed_handler(): %s\n", "VehicleOdometer");
-                return ;
-       }
-
-       g_timeout_add_seconds(10, timer_callback, "VehicleOdometer");
-
-       loop = g_main_loop_new(NULL, FALSE);
-       g_main_loop_run(loop);
-
-       g_main_loop_unref(loop);
-}
-
 static void test_samsungcan_GearboxPosition()
 {
        struct GearboxPositionDisplayType *p;
@@ -254,7 +171,7 @@ static void test_LampHazardLight()
        amb_release_data(p);
 }
 
-static void LampHazardLight_handler(const gchar *objname, gpointer data)
+static void LampHazardLight_handler(const gchar *objname, gpointer data, void *user_data)
 {
        struct LampHazardLightType retdata;
 
@@ -270,26 +187,6 @@ static void LampHazardLight_handler(const gchar *objname, gpointer data)
        fprintf(stderr, "    Time: %f\n", retdata.Time);
 }
 
-static void test_LampHazardLight_listen()
-{
-       GMainLoop *loop;
-       int rc;
-
-       rc = amb_register_property_changed_handler("LampHazardLight", 0,
-                       (AMB_PROPERTY_CHANGED_CALLBACK)LampHazardLight_handler);
-       if (rc != 0) {
-                fprintf(stderr, "Fail to amb_register_property_changed_handler(): %s\n", "LampHazardLight");
-                return ;
-       }
-
-       g_timeout_add_seconds(10, timer_callback, "LampHazardLight");
-
-       loop = g_main_loop_new(NULL, FALSE);
-       g_main_loop_run(loop);
-
-       g_main_loop_unref(loop);
-}
-
 static void test_WarningSafetybelts()
 {
        struct WarningSafetybeltsType *p;
@@ -307,42 +204,6 @@ static void test_WarningSafetybelts()
        amb_release_data(p);
 }
 
-static void WarningSafetybelts_handler(const gchar *objname, gpointer data)
-{
-       struct WarningSafetybeltsType retdata;
-
-       if (!data)
-               return ;
-
-       amb_convert_WarningSafetybeltsType(data, &retdata);
-
-       fprintf(stderr, " == WarningSafetybelts ==\n");
-       fprintf(stderr, "    Zone: %d\n", retdata.Zone);
-       fprintf(stderr, "    Value: %s\n", (retdata.Value) ? "Set" : "None");
-       fprintf(stderr, "    ValueSequence: %d\n", retdata.ValueSequence);
-       fprintf(stderr, "    Time: %f\n", retdata.Time);
-}
-
-static void test_WarningSafetybelts_listen()
-{
-       GMainLoop *loop;
-       int rc;
-
-       rc = amb_register_property_changed_handler("WarningSafetybelts", 0,
-                       (AMB_PROPERTY_CHANGED_CALLBACK)WarningSafetybelts_handler);
-       if (rc != 0) {
-                fprintf(stderr, "Fail to amb_register_property_changed_handler(): %s\n", "WarningSafetybelts");
-                return ;
-       }
-
-       g_timeout_add_seconds(10, timer_callback, "WarningSafetybelts");
-
-       loop = g_main_loop_new(NULL, FALSE);
-       g_main_loop_run(loop);
-
-       g_main_loop_unref(loop);
-}
-
 static void test_samsungcan_VehicleOdometer()
 {
        struct VehicleOdometerType *p;
@@ -371,7 +232,6 @@ static void test_TPMS_FL()
        }
        fprintf(stderr, " == TPMS_FL ==\n");
        fprintf(stderr, "    Zone: %d\n", p->Zone);
-       // fprintf(stderr, "    Value: %u\n", (unsigned int)p->Value);
        fprintf(stderr, "    Value: %u\n", p->Value);
        fprintf(stderr, "    ValueSequence: %d\n", p->ValueSequence);
        fprintf(stderr, "    Time: %f\n", p->Time);
@@ -379,42 +239,6 @@ static void test_TPMS_FL()
        amb_release_data(p);
 }
 
-static void TPMS_FL_handler(const gchar *objname, gpointer data)
-{
-       struct TPMS_FLType retdata;
-
-       if (!data)
-               return ;
-
-       amb_convert_TPMS_FLType(data, &retdata);
-
-       fprintf(stderr, " == TPMS_FL ==\n");
-       fprintf(stderr, "    Zone: %d\n", retdata.Zone);
-       fprintf(stderr, "    Value: %u\n", retdata.Value);
-       fprintf(stderr, "    ValueSequence: %d\n", retdata.ValueSequence);
-       fprintf(stderr, "    Time: %f\n", retdata.Time);
-}
-
-static void test_TPMS_FL_listen()
-{
-       GMainLoop *loop;
-       int rc;
-
-       rc = amb_register_property_changed_handler("TPMS_FL", 0,
-                       (AMB_PROPERTY_CHANGED_CALLBACK)TPMS_FL_handler);
-       if (rc != 0) {
-                fprintf(stderr, "Fail to amb_register_property_changed_handler(): %s\n", "WarningSafetybelts");
-                return ;
-       }
-
-       g_timeout_add_seconds(10, timer_callback, "TPMS_FL");
-
-       loop = g_main_loop_new(NULL, FALSE);
-       g_main_loop_run(loop);
-
-       g_main_loop_unref(loop);
-}
-
 static void test_FuelGage()
 {
        struct FuelGageType *p;
@@ -467,25 +291,138 @@ static void test_FR_KeyEvent02()
        amb_release_data(p);
 }
 
+/*****************************************************************************/
+
+struct user_data_test {
+       int value;
+       char *name;
+};
+
+struct user_data_test *udata;
+struct user_data_test *udata2;
+
+static int convert_VehicleOdometerType(GVariant *data, struct VehicleOdometerType *retdata)
+{
+       GVariantIter *iter;
+       gchar *key;
+       GVariant *value;
+       GVariant *gdata;
+
+       gdata = (GVariant *)data;
+
+       
+       g_variant_get(gdata, "a{sv}", &iter);
+       while(g_variant_iter_loop(iter, "{sv}", &key, &value)) {
+               if (!g_strcmp0(key, "Zone")) {
+                       g_variant_get(value, "i", &retdata->Zone);
+                       fprintf(stderr, "%s: %d\n", key, retdata->Zone);
+               } else if (!g_strcmp0(key, "ValueSequence") || !g_strcmp0(key, "ValueSequence")) {
+                       g_variant_get(value, "i", &retdata->ValueSequence);
+                       fprintf(stderr, "%s: %d\n", key, retdata->ValueSequence);
+               } else if (!g_strcmp0(key, "Time")) {
+                       g_variant_get(value, "d", &retdata->Time);
+                       fprintf(stderr, "%s: %f\n", key, retdata->Time);
+               } else if (!g_strcmp0(key, "Value") || !g_strcmp0(key, "Vaule")) {
+                       g_variant_get(value, "u", &retdata->Value);
+                       fprintf(stderr, "%s: %d\n", key, retdata->Value);
+               }
+       }
+       g_variant_iter_free(iter);
+       return 0;
+}
+
+static void VehicleOdometer_handler(const gchar *objname, gpointer data, void *user_data)
+{
+       struct VehicleOdometerType retdata;
+       struct user_data_test *udata = (struct user_data_test *)user_data;
+
+       fprintf(stderr, "== User Data ==\n");
+       fprintf(stderr, "  value: %d\n", udata->value);
+       fprintf(stderr, "  name: %s\n", udata->name);
+
+
+       if (!data)
+               return ;
+
+       convert_VehicleOdometerType(data, &retdata);
+}
+
+static gboolean timer_callback(gpointer d)
+{
+       free(udata->name);
+       g_free(udata);
+       exit(0);
+
+       return FALSE;
+}
+
+static void test_VehicleOdometer_listen()
+{
+       GMainLoop *loop;
+       guint32 id1;
+       guint32 id2;
+       int rc;
+
+       udata = g_new0(struct user_data_test, 1);
+       udata->value = 20;
+       udata->name = strdup("Test Name");
+
+       rc = amb_register_property_changed_handler("VehicleOdometer",
+                                       0,
+                                       (AMB_PROPERTY_CHANGED_CALLBACK)VehicleOdometer_handler,
+                                       (void *)udata, &id1);
+       if (rc != 0) {
+                fprintf(stderr, "Fail to amb_register_property_changed_handler(): %s\n", "VehicleOdometer");
+                return ;
+       }
+
+       udata2 = g_new0(struct user_data_test, 1);
+       udata2->value = 100;
+       udata2->name = strdup("Test Name2");
+       rc = amb_register_property_changed_handler("VehicleOdometer",
+                                       0,
+                                       (AMB_PROPERTY_CHANGED_CALLBACK)VehicleOdometer_handler,
+                                       (void *)udata2, &id2);
+       if (rc != 0) {
+                fprintf(stderr, "Fail to amb_register_property_changed_handler(): %s\n", "VehicleOdometer");
+                return ;
+       }
+       fprintf(stderr, "id1: %u, id2: %u\n", id1, id2);
+
+#if 0
+       rc = amb_unregister_property_changed_handler("VehicleOdometer", 0, id1);
+       if (rc != 0) {
+                fprintf(stderr, "Fail to amb_unregister_property_changed_handler(): %u\n", id1);
+               return ;
+       }
+#endif
+
+       // g_timeout_add_seconds(10, timer_callback, "VehicleOdometer");
+       loop = g_main_loop_new(NULL, FALSE);
+       g_main_loop_run(loop);
+
+       g_main_loop_unref(loop);
+}
+
+
 
 int main()
 {
-       test_get_object_list();
+       test_VehicleOdometer_listen();
 
-       // cansend vcan0 207#03.00.00.00.00.00.00.00
        test_FR_KeyEvent01();
        test_FR_KeyEvent02();
 
+       test_get_object_list();
+
        // cansend vcan0 104#3C.00.00.00.00.00.00.00
        test_FuelGage();
 
        // cansend vcan0 104#3C.00.00.00.00.00.00.00
        test_TPMS_FL();
-       test_TPMS_FL_listen();
 
        // cansend vcan0 206#00.00.00.00.01.00.00.00
        test_LampHazardLight();
-       test_LampHazardLight_listen();
 
        // cansend vcan0 206#01.00.00.00.00.00.00.00
        test_WarningSafetybelts();
@@ -494,8 +431,6 @@ int main()
        test_samsungcan_VehicleSpeed();
        test_samsungcan_GearboxPosition();
 
-       test_VehicleOdometer_listen();
-
 #ifdef EXAMPLE_PLUGIN
        test_get_property_all("ClimateControl");
        test_get_property_all("VehicleSpeed");
@@ -504,8 +439,6 @@ int main()
 
        test_set_property("ClimateControl", "AirConditioning", 5, g_variant_new("b", TRUE));
 
-       test_signal_listen("VehicleSpeed", 0);
-
        test_samsungcan_GearboxPosition();
 #endif