Clean up all resource for non-threaded IPC.
authorSung-jae Park <nicesj.park@samsung.com>
Thu, 22 May 2014 02:18:22 +0000 (11:18 +0900)
committerSung-jae Park <nicesj.park@samsung.com>
Thu, 22 May 2014 02:18:22 +0000 (11:18 +0900)
Change-Id: I50c9f6f02580d8390307045278fdef0999a65cbb

include/com-core_internal.h
packaging/libcom-core.spec
src/com-core.c
src/com-core_thread.c

index 1523d05..667a48d 100644 (file)
@@ -15,7 +15,7 @@
  *
 */
 
-extern void invoke_con_cb_list(int handle);
-extern void invoke_disconn_cb_list(int handle);
+extern void invoke_con_cb_list(int server_fd, int handle, guint id, void *data, int watch);
+extern void invoke_disconn_cb_list(int handle, int remove_id, int remove_data, int watch);
 
 /* End of a file */
index 8e27d57..e56cc20 100644 (file)
@@ -1,6 +1,6 @@
 Name: libcom-core
 Summary: Library for the light-weight IPC 
-Version: 0.5.9
+Version: 0.5.10
 Release: 1
 Group: Base/IPC
 License: Apache-2.0
index d254014..f1973f7 100644 (file)
@@ -37,6 +37,7 @@
 #include "util.h"
 
 static struct {
+       struct dlist *watch_list;
        struct dlist *conn_cb_list;
        struct dlist *disconn_cb_list;
        enum processing_event_callback {
@@ -45,11 +46,19 @@ static struct {
                PROCESSING_CONNECTION = 0x02,
        } processing_event_callback;
 } s_info = {
+       .watch_list = NULL,
        .conn_cb_list = NULL,
        .disconn_cb_list = NULL,
        .processing_event_callback = PROCESSING_NONE,
 };
 
+struct watch_item {
+       int server_fd;
+       int fd;
+       guint id;
+       void *cbdata;
+};
+
 struct cbdata {
        int (*service_cb)(int fd, void *data);
        void *data;
@@ -61,12 +70,93 @@ struct evtdata {
        void *data;
 };
 
-HAPI void invoke_con_cb_list(int handle)
+static int watch_item_create(int server_fd, int handle, guint id, void *cbdata)
+{
+       struct watch_item *item;
+
+       item = malloc(sizeof(*item));
+       if (!item) {
+               return -ENOMEM;
+       }
+
+       item->server_fd = server_fd;
+       item->fd = handle;
+       item->id = id;
+       item->cbdata = cbdata;
+
+       DbgPrint("Watch Item is created for %d/%d\n", server_fd, handle);
+       s_info.watch_list = dlist_append(s_info.watch_list, item);
+       return 0;
+}
+
+static int watch_item_destroy(int handle, int remove_id, int remove_cbdata)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct watch_item *item;
+
+       dlist_foreach_safe(s_info.watch_list, l, n, item) {
+               if (item->fd == handle) {
+                       s_info.watch_list = dlist_remove(s_info.watch_list, l);
+
+                       DbgPrint("Watch item is destroyed for %d/%d\n", item->server_fd, item->fd);
+
+                       if (remove_id && item->id) {
+                               g_source_remove(item->id);
+                       }
+
+                       if (remove_cbdata && item->cbdata) {
+                               free(item->cbdata);
+                       }
+
+                       free(item);
+                       return 0;
+               }
+       }
+
+       DbgPrint("No entry found\n");
+       return -ENOENT;
+}
+
+static void watch_item_destroy_all(int socket_fd)
+{
+       struct dlist *l;
+       struct dlist *n;
+       struct watch_item *item;
+
+       dlist_foreach_safe(s_info.watch_list, l, n, item) {
+               if (item->server_fd == socket_fd) {
+                       DbgPrint("Watch item removed: %d/%d\n", item->server_fd, item->fd);
+                       /*!
+                        * \WARN
+                        * If the watch_list item is removed from disconnected
+                        * callback, this list loop can be broken.
+                        * Please check it again.
+                        */
+                       invoke_disconn_cb_list(item->fd, 0, 0, 0);
+
+                       s_info.watch_list = dlist_remove(s_info.watch_list, l);
+                       if (item->id > 0) {
+                               g_source_remove(item->id);
+                       }
+                       free(item->cbdata);
+                       free(item);
+               }
+       }
+}
+
+HAPI void invoke_con_cb_list(int server_fd, int handle, guint id, void *data, int watch)
 {
        struct dlist *l;
        struct dlist *n;
        struct evtdata *cbdata;
 
+       if (watch) {
+               if (watch_item_create(server_fd, handle, id, data) < 0) {
+                       ErrPrint("Failed to create a watch item\n");
+               }
+       }
+
        s_info.processing_event_callback |= PROCESSING_CONNECTION;
        dlist_foreach_safe(s_info.conn_cb_list, l, n, cbdata) {
                /*!
@@ -82,7 +172,7 @@ HAPI void invoke_con_cb_list(int handle)
        s_info.processing_event_callback &= ~PROCESSING_CONNECTION;
 }
 
-HAPI void invoke_disconn_cb_list(int handle)
+HAPI void invoke_disconn_cb_list(int handle, int remove_id, int remove_data, int watch)
 {
        struct dlist *l;
        struct dlist *n;
@@ -101,6 +191,12 @@ HAPI void invoke_disconn_cb_list(int handle)
                }
        }
        s_info.processing_event_callback &= ~PROCESSING_DISCONNECTION;
+
+       if (watch) {
+               if (watch_item_destroy(handle, remove_id, remove_data) < 0) {
+                       ErrPrint("Failed to destroy watch item\n");
+               }
+       }
 }
 
 static int validate_handle(int fd)
@@ -127,14 +223,14 @@ static gboolean client_cb(GIOChannel *src, GIOCondition cond, gpointer data)
 
        if (!(cond & G_IO_IN)) {
                DbgPrint("Client is disconencted\n");
-               invoke_disconn_cb_list(client_fd);
+               invoke_disconn_cb_list(client_fd, 0, 1, 1);
                secure_socket_destroy_handle(client_fd);
                return FALSE;
        }
 
        if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
                DbgPrint("Client connection is lost\n");
-               invoke_disconn_cb_list(client_fd);
+               invoke_disconn_cb_list(client_fd, 0, 1, 1);
                secure_socket_destroy_handle(client_fd);
                return FALSE;
        }
@@ -142,13 +238,19 @@ static gboolean client_cb(GIOChannel *src, GIOCondition cond, gpointer data)
        ret = cbdata->service_cb(client_fd, cbdata->data);
        if (ret < 0) {
                DbgPrint("service callback returns %d < 0\n", ret);
-               invoke_disconn_cb_list(client_fd);
+               invoke_disconn_cb_list(client_fd, 0, 1, 1);
                secure_socket_destroy_handle(client_fd);
                return FALSE;
        }
 
        /* Check whether the socket FD is closed or not */
-       return validate_handle(client_fd) ? TRUE : FALSE;
+       if (!validate_handle(client_fd)) {
+               invoke_disconn_cb_list(client_fd, 0, 1, 1);
+               secure_socket_destroy_handle(client_fd);
+               return FALSE;
+       }
+
+       return TRUE;
 }
 
 static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata)
@@ -161,6 +263,7 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata)
        socket_fd = g_io_channel_unix_get_fd(src);
        if (!(cond & G_IO_IN)) {
                ErrPrint("Accept socket closed\n");
+               watch_item_destroy_all(socket_fd);
                secure_socket_destroy_handle(socket_fd);
                free(cbdata);
                return FALSE;
@@ -168,6 +271,7 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata)
 
        if ((cond & G_IO_ERR) || (cond & G_IO_HUP) || (cond & G_IO_NVAL)) {
                ErrPrint("Client connection is lost\n");
+               watch_item_destroy_all(socket_fd);
                secure_socket_destroy_handle(socket_fd);
                free(cbdata);
                return FALSE;
@@ -175,8 +279,8 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata)
 
        client_fd = secure_socket_get_connection_handle(socket_fd);
        if (client_fd < 0) {
-               free(cbdata);
-               return FALSE;
+               /* Keep server running */
+               return TRUE;
        }
        DbgPrint("New connectino arrived: server(%d), client(%d)\n", socket_fd, client_fd);
 
@@ -192,8 +296,8 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata)
        if (!gio) {
                ErrPrint("Failed to get gio\n");
                secure_socket_destroy_handle(client_fd);
-               free(cbdata);
-               return FALSE;
+               /* Keep server running */
+               return TRUE;
        }
 
        g_io_channel_set_close_on_unref(gio, FALSE);
@@ -201,6 +305,7 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata)
        id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)client_cb, cbdata);
        if (id <= 0) {
                GError *err = NULL;
+
                ErrPrint("Failed to add IO watch\n");
                g_io_channel_shutdown(gio, TRUE, &err);
                if (err) {
@@ -209,14 +314,21 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer cbdata)
                }
                g_io_channel_unref(gio);
                secure_socket_destroy_handle(client_fd);
-               free(cbdata);
-               return FALSE;
+               /* Keep server running */
+               return TRUE;
        }
 
        g_io_channel_unref(gio);
 
-       invoke_con_cb_list(client_fd);
-       return validate_handle(socket_fd) ? TRUE : FALSE;
+       invoke_con_cb_list(socket_fd, client_fd, id, NULL, 1);
+
+       if (!validate_handle(socket_fd)) {
+               watch_item_destroy_all(socket_fd);
+               return FALSE;
+       }
+
+       /* Keep server running */
+       return TRUE;
 }
 
 EAPI int com_core_server_create(const char *addr, int is_sync, int (*service_cb)(int fd, void *data), void *data)
@@ -275,6 +387,23 @@ EAPI int com_core_server_create(const char *addr, int is_sync, int (*service_cb)
                return -EIO;
        }
 
+       if (watch_item_create(fd, fd, id, cbdata) < 0) {
+               GError *err = NULL;
+
+               ErrPrint("Failed to create a watch item\n");
+               g_source_remove(id);
+
+               free(cbdata);
+               g_io_channel_shutdown(gio, TRUE, &err);
+               if (err) {
+                       ErrPrint("Shutdown: %s\n", err->message);
+                       g_error_free(err);
+               }
+               g_io_channel_unref(gio);
+               secure_socket_destroy_handle(fd);
+               return -ENOMEM;
+       }
+
        g_io_channel_unref(gio);
        return fd;
 }
@@ -336,7 +465,7 @@ EAPI int com_core_client_create(const char *addr, int is_sync, int (*service_cb)
 
        g_io_channel_unref(gio);
 
-       invoke_con_cb_list(client_fd);
+       invoke_con_cb_list(client_fd, client_fd, id, cbdata, 1);
        return client_fd;
 }
 
@@ -534,7 +663,7 @@ EAPI void *com_core_del_event_callback(enum com_core_event_type type, int (*cb)(
 EAPI int com_core_server_destroy(int handle)
 {
        DbgPrint("Close server handle[%d]\n", handle);
-       invoke_disconn_cb_list(handle);
+       invoke_disconn_cb_list(handle, 1, 1, 1);
        secure_socket_destroy_handle(handle);
        return 0;
 }
@@ -542,7 +671,7 @@ EAPI int com_core_server_destroy(int handle)
 EAPI int com_core_client_destroy(int handle)
 {
        DbgPrint("Close client handle[%d]\n", handle);
-       invoke_disconn_cb_list(handle);
+       invoke_disconn_cb_list(handle, 1, 1, 1);
        secure_socket_destroy_handle(handle);
        return 0;
 }
index eaa88b5..2a8fc5a 100644 (file)
@@ -499,7 +499,7 @@ static gboolean evt_pipe_cb(GIOChannel *src, GIOCondition cond, gpointer data)
 
 errout:
        DbgPrint("Disconnecting\n");
-       invoke_disconn_cb_list(tcb->handle);
+       invoke_disconn_cb_list(tcb->handle, 0, 0, 0);
        terminate_thread(tcb);
        tcb_destroy(tcb);
        return FALSE;
@@ -624,6 +624,7 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data)
        }
 
        g_io_channel_set_close_on_unref(gio, FALSE);
+
        tcb->id = g_io_add_watch(gio, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, (GIOFunc)evt_pipe_cb, tcb);
        if (tcb->id == 0) {
                GError *err = NULL;
@@ -641,12 +642,12 @@ static gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data)
        }
        g_io_channel_unref(gio);
 
-       invoke_con_cb_list(tcb->handle);
+       invoke_con_cb_list(tcb->handle, tcb->handle, 0, NULL, 0);
 
        ret = pthread_create(&tcb->thid, NULL, client_cb, tcb);
        if (ret != 0) {
                ErrPrint("Thread creation failed: %s\n", strerror(ret));
-               invoke_disconn_cb_list(tcb->handle);
+               invoke_disconn_cb_list(tcb->handle, 0, 0, 0);
                secure_socket_destroy_handle(tcb->handle);
                tcb_destroy(tcb);
                server_destroy(server);
@@ -717,12 +718,12 @@ EAPI int com_core_thread_client_create(const char *addr, int is_sync, int (*serv
 
        g_io_channel_unref(gio);
 
-       invoke_con_cb_list(tcb->handle);
+       invoke_con_cb_list(tcb->handle, tcb->handle, 0, NULL, 0);
 
        ret = pthread_create(&tcb->thid, NULL, client_cb, tcb);
        if (ret != 0) {
                ErrPrint("Thread creation failed: %s\n", strerror(ret));
-               invoke_disconn_cb_list(tcb->handle);
+               invoke_disconn_cb_list(tcb->handle, 0, 0, 0);
                secure_socket_destroy_handle(tcb->handle);
                tcb_destroy(tcb);
                return -EFAULT;
@@ -972,7 +973,7 @@ EAPI int com_core_thread_server_destroy(int handle)
                        continue;
                }
 
-               invoke_disconn_cb_list(handle);
+               invoke_disconn_cb_list(handle, 0, 0, 0);
                terminate_thread(tcb);
                tcb_destroy(tcb);
                return 0;
@@ -983,7 +984,7 @@ EAPI int com_core_thread_server_destroy(int handle)
                        continue;
                }
 
-               invoke_disconn_cb_list(handle);
+               invoke_disconn_cb_list(handle, 0, 0, 0);
                server_destroy(server);
                return 0;
        }
@@ -1004,7 +1005,7 @@ EAPI int com_core_thread_client_destroy(int handle)
                return -ENOENT;
        }
 
-       invoke_disconn_cb_list(handle);
+       invoke_disconn_cb_list(handle, 0, 0, 0);
        terminate_thread(tcb);
        tcb_destroy(tcb);
        return 0;