Base Code merged to SPIN 2.4
[platform/upstream/connman.git] / src / inotify.c
old mode 100644 (file)
new mode 100755 (executable)
index f451f1c..c251c6f
@@ -3,7 +3,7 @@
  *  Connection Manager
  *
  *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
- *  Copyright (C) 2012  BMW Car IT GmbH. All rights reserved.
+ *  Copyright (C) 2012-2014  BMW Car IT GmbH.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -35,6 +35,8 @@
 #include "connman.h"
 
 struct connman_inotify {
+       unsigned int refcount;
+
        GIOChannel *channel;
        uint watch;
        int wd;
@@ -42,13 +44,30 @@ struct connman_inotify {
        GSList *list;
 };
 
+static void cleanup_inotify(gpointer user_data);
+
+static void connman_inotify_ref(struct connman_inotify *i)
+{
+       __sync_fetch_and_add(&i->refcount, 1);
+}
+
+static void connman_inotify_unref(gpointer data)
+{
+       struct connman_inotify *i = data;
+
+       if (__sync_fetch_and_sub(&i->refcount, 1) != 1)
+               return;
+
+       cleanup_inotify(data);
+}
+
 static GHashTable *inotify_hash;
 
 static gboolean inotify_data(GIOChannel *channel, GIOCondition cond,
                                                        gpointer user_data)
 {
        struct connman_inotify *inotify = user_data;
-       char buffer[256];
+       char buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
        char *next_event;
        gsize bytes_read;
        GIOStatus status;
@@ -60,7 +79,7 @@ static gboolean inotify_data(GIOChannel *channel, GIOCondition cond,
        }
 
        status = g_io_channel_read_chars(channel, buffer,
-                                       sizeof(buffer) -1, &bytes_read, NULL);
+                                       sizeof(buffer), &bytes_read, NULL);
 
        switch (status) {
        case G_IO_STATUS_NORMAL:
@@ -75,6 +94,8 @@ static gboolean inotify_data(GIOChannel *channel, GIOCondition cond,
 
        next_event = buffer;
 
+       connman_inotify_ref(inotify);
+
        while (bytes_read > 0) {
                struct inotify_event *event;
                gchar *ident;
@@ -95,13 +116,15 @@ static gboolean inotify_data(GIOChannel *channel, GIOCondition cond,
                next_event += len;
                bytes_read -= len;
 
-               for (list = inotify->list; list != NULL; list = list->next) {
+               for (list = inotify->list; list; list = list->next) {
                        inotify_event_cb callback = list->data;
 
                        (*callback)(event, ident);
                }
        }
 
+       connman_inotify_unref(inotify);
+
        return TRUE;
 }
 
@@ -125,7 +148,7 @@ static int create_watch(const char *path, struct connman_inotify *inotify)
        }
 
        inotify->channel = g_io_channel_unix_new(fd);
-       if (inotify->channel == NULL) {
+       if (!inotify->channel) {
                connman_error("Creation of inotify channel failed");
                inotify_rm_watch(fd, inotify->wd);
                inotify->wd = 0;
@@ -149,7 +172,7 @@ static void remove_watch(struct connman_inotify *inotify)
 {
        int fd;
 
-       if (inotify->channel == NULL)
+       if (!inotify->channel)
                return;
 
        if (inotify->watch > 0)
@@ -168,17 +191,18 @@ int connman_inotify_register(const char *path, inotify_event_cb callback)
        struct connman_inotify *inotify;
        int err;
 
-       if (callback == NULL)
+       if (!callback)
                return -EINVAL;
 
        inotify = g_hash_table_lookup(inotify_hash, path);
-       if (inotify != NULL)
+       if (inotify)
                goto update;
 
        inotify = g_try_new0(struct connman_inotify, 1);
-       if (inotify == NULL)
+       if (!inotify)
                return -ENOMEM;
 
+       inotify->refcount = 1;
        inotify->wd = -1;
 
        err = create_watch(path, inotify);
@@ -210,11 +234,11 @@ void connman_inotify_unregister(const char *path, inotify_event_cb callback)
        struct connman_inotify *inotify;
 
        inotify = g_hash_table_lookup(inotify_hash, path);
-       if (inotify == NULL)
+       if (!inotify)
                return;
 
        inotify->list = g_slist_remove(inotify->list, callback);
-       if (inotify->list != NULL)
+       if (inotify->list)
                return;
 
        g_hash_table_remove(inotify_hash, path);
@@ -225,7 +249,7 @@ int __connman_inotify_init(void)
        DBG("");
 
        inotify_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
-                                               g_free, cleanup_inotify);
+                                               g_free, connman_inotify_unref);
        return 0;
 }