audiod: Fix memory leak on exit: stat client.
authorAndre Noll <maan@systemlinux.org>
Sun, 7 Jul 2013 12:02:40 +0000 (14:02 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 22 Sep 2013 00:29:18 +0000 (02:29 +0200)
Currently we don't close stat clients on exit which results in (benign)
memory leaks. Introduce the new public close_stat_clients() and call
it from clean_exit() to avoid the leak.

This patch also removes the pointles local variable "fd".

audiod.c
audiod.h
audiod_command.c

index 2367d9c..6afb15e 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -1143,6 +1143,7 @@ void __noreturn clean_exit(int status, const char *msg)
        FOR_EACH_SLOT(i)
                close_slot(i);
        audiod_cmdline_parser_free(&conf);
        FOR_EACH_SLOT(i)
                close_slot(i);
        audiod_cmdline_parser_free(&conf);
+       close_stat_clients();
        exit(status);
 }
 
        exit(status);
 }
 
index e54a857..6a1e8f6 100644 (file)
--- a/audiod.h
+++ b/audiod.h
@@ -74,6 +74,7 @@ struct btr_node *audiod_get_btr_root(void);
 
 void stat_client_write_item(int item_num);
 void clear_and_dump_items(void);
 
 void stat_client_write_item(int item_num);
 void clear_and_dump_items(void);
+void close_stat_clients(void);
 
 /** iterate over all slots */
 #define FOR_EACH_SLOT(_slot) for (_slot = 0; _slot < MAX_STREAM_SLOTS; _slot++)
 
 /** iterate over all slots */
 #define FOR_EACH_SLOT(_slot) for (_slot = 0; _slot < MAX_STREAM_SLOTS; _slot++)
index 332ce85..118c22a 100644 (file)
@@ -109,6 +109,31 @@ static int stat_client_add(int fd, uint64_t mask, int parser_friendly)
        num_clients++;
        return 1;
 }
        num_clients++;
        return 1;
 }
+
+static void close_stat_client(struct stat_client *sc)
+{
+       PARA_INFO_LOG("closing client fd %d\n", sc->fd);
+       close(sc->fd);
+       list_del(&sc->node);
+       free(sc);
+       num_clients--;
+}
+
+/**
+ * Empty the status clients list.
+ *
+ * This iterates over the list of connected status clients, closes each client
+ * file descriptor and frees the resources.
+ */
+void close_stat_clients(void)
+{
+       struct stat_client *sc, *tmp;
+
+       list_for_each_entry_safe(sc, tmp, &client_list, node)
+               close_stat_client(sc);
+       assert(num_clients == 0);
+}
+
 /**
  * Write a message to all connected status clients.
  *
 /**
  * Write a message to all connected status clients.
  *
@@ -127,7 +152,7 @@ void stat_client_write_item(int item_num)
        struct para_buffer *b;
 
        list_for_each_entry_safe(sc, tmp, &client_list, node) {
        struct para_buffer *b;
 
        list_for_each_entry_safe(sc, tmp, &client_list, node) {
-               int fd = sc->fd, ret;
+               int ret;
 
                if (!((one << item_num) & sc->item_mask))
                        continue;
 
                if (!((one << item_num) & sc->item_mask))
                        continue;
@@ -135,15 +160,11 @@ void stat_client_write_item(int item_num)
                if (!b->buf)
                        (void)WRITE_STATUS_ITEM(b, item_num, "%s\n",
                                msg? msg : "");
                if (!b->buf)
                        (void)WRITE_STATUS_ITEM(b, item_num, "%s\n",
                                msg? msg : "");
-               ret = write(fd, b->buf, b->offset);
+               ret = write(sc->fd, b->buf, b->offset);
                if (ret == b->offset)
                        continue;
                /* write error or short write */
                if (ret == b->offset)
                        continue;
                /* write error or short write */
-               close(fd);
-               num_clients--;
-               PARA_INFO_LOG("deleting client on fd %d\n", fd);
-               list_del(&sc->node);
-               free(sc);
+               close_stat_client(sc);
                dump_stat_client_list();
        }
        free(pb.buf);
                dump_stat_client_list();
        }
        free(pb.buf);