Remove poll in sending notis to client 87/114687/5
authorJiwoong Im <jiwoong.im@samsung.com>
Mon, 6 Feb 2017 08:13:02 +0000 (17:13 +0900)
committerJiwoong Im <jiwoong.im@samsung.com>
Tue, 7 Mar 2017 05:10:58 +0000 (21:10 -0800)
- If the client is too busy to handle the noti callback, it
  causes buxton daemon to block in poll function.
  To prevent being blocked, remove poll in sending notis to client.
  If the result of noti send is EWOULDBLOCK or EAGAIN, wait until
  the socket fd is writable in the main loop and send it again.

Change-Id: I5c3e54495667cd927182de3323c0a97015e561f4
Signed-off-by: Jiwoong Im <jiwoong.im@samsung.com>
(cherry picked from commit 7d4c9d38b654ba340a02187d42d3a5d17ed6ba6b)

common/proto.c
daemon/daemon.c
daemon/daemon.h

index 48d2b8b..73a4b20 100644 (file)
@@ -400,26 +400,28 @@ int proto_send(int fd, enum message_type type, uint8_t *data, int32_t len)
        fds[0].events = POLLOUT;
        fds[0].revents = 0;
 
-       do {
-               r = poll(fds, 1, SEND_TIMEOUT);
-               if (r == -1) {
-                       if (errno == EINTR)
-                               continue;
-
-                       bxt_err("send: fd %d poll errno %d", fd, errno);
-                       free(buf);
-
-                       return -1;
-               }
-
-               if (r == 0) {
-                       bxt_err("send: fd %d poll timeout", fd);
-                       free(buf);
-                       errno = ETIMEDOUT;
-
-                       return -1;
-               }
-       } while (r < 0);
+       if (type != MSG_NOTI) {
+               do {
+                       r = poll(fds, 1, SEND_TIMEOUT);
+                       if (r == -1) {
+                               if (errno == EINTR)
+                                       continue;
+
+                               bxt_err("send: fd %d poll errno %d", fd, errno);
+                               free(buf);
+
+                               return -1;
+                       }
+
+                       if (r == 0) {
+                               bxt_err("send: fd %d poll timeout", fd);
+                               free(buf);
+                               errno = ETIMEDOUT;
+
+                               return -1;
+                       }
+               } while (r < 0);
+       }
 
        r = send(fd, buf, sizeof(*hdr) + len, MSG_NOSIGNAL);
 
index e440308..a827263 100644 (file)
@@ -210,6 +210,45 @@ static char *get_search_key_u(const struct buxton_layer *layer, const char *key)
        return get_search_key(layer, key, u);
 }
 
+static gboolean _send_notis(gpointer key, gpointer value, gpointer data)
+{
+       int r;
+       guchar *_data;
+       gsize _len;
+       struct bxt_client *cli = (struct bxt_client *)data;
+       gchar *g_data = (gchar *)value;
+
+       _data = g_base64_decode(g_data, &_len);
+
+       r = proto_send(cli->fd, MSG_NOTI, (uint8_t *)_data, (int)_len);
+       if (r == -1) {
+               bxt_err("send noti again key : %s pid : %d errno : %d",
+                               key, cli->cred.pid, errno);
+               if (errno == EWOULDBLOCK || errno == EAGAIN) {
+                       free(_data);
+                       return FALSE;
+               }
+       }
+
+       free(_data);
+       return TRUE;
+}
+
+static gboolean _send_delayed_noti(gint fd, GIOCondition cond, gpointer data)
+{
+       struct bxt_client *cli = (struct bxt_client *)data;
+
+       if (cli->delay_notilist && g_hash_table_size(cli->delay_notilist) > 0)
+               g_hash_table_foreach_remove(cli->delay_notilist,
+                               (GHRFunc)_send_notis, cli);
+
+       if (g_hash_table_size(cli->delay_notilist) > 0)
+               return G_SOURCE_CONTINUE;
+
+       cli->fd_out_id = 0;
+       return G_SOURCE_REMOVE;
+}
+
 static void send_notis(struct bxt_daemon *bxtd, struct request *rqst)
 {
        int r;
@@ -219,6 +258,7 @@ static void send_notis(struct bxt_daemon *bxtd, struct request *rqst)
        struct request req;
        uint8_t *data;
        int len;
+       gchar *_data;
 
        assert(bxtd);
        assert(rqst);
@@ -248,8 +288,31 @@ static void send_notis(struct bxt_daemon *bxtd, struct request *rqst)
                struct bxt_client *cli = l->data;
 
                r = proto_send(cli->fd, req.type, data, len);
-               if (r == -1)
-                       bxt_err("send notis: cli %p error %d", cli, errno);
+               if (r == -1) {
+                       bxt_err("send notis: cli pid : %d  label : %s key : %s error %d",
+                                       cli->cred.pid, cli->label, rqst->key, errno);
+                       if (errno == EWOULDBLOCK || errno == EAGAIN) {
+                               _data = g_base64_encode(data, len);
+
+                               if (cli->fd_out_id == 0) {
+                                       cli->fd_out_id = g_unix_fd_add_full(G_PRIORITY_DEFAULT,
+                                                       cli->fd, G_IO_OUT, _send_delayed_noti,
+                                                       cli, NULL);
+                               }
+                               if (!cli->delay_notilist) {
+                                       cli->delay_notilist = g_hash_table_new_full(g_str_hash,
+                                                       g_str_equal,
+                                                       (GDestroyNotify)free,
+                                                       (GDestroyNotify)g_free);
+                               }
+
+                               g_hash_table_replace(cli->delay_notilist,
+                                               strdup(rqst->key), _data);
+                       }
+               } else {
+                       if (cli->delay_notilist)
+                               g_hash_table_remove(cli->delay_notilist, rqst->key);
+               }
        }
 
        free(data);
@@ -827,6 +890,8 @@ static void add_client(struct bxt_daemon *bxtd, int fd)
                        G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                        client_cb, cli);
 
+       cli->fd_out_id = 0;
+
        g_hash_table_insert(bxtd->clients, cli, cli);
        bxt_dbg("Client %p added, fd %d", cli, fd);
 }
@@ -880,9 +945,15 @@ static void free_client(struct bxt_client *cli)
        g_list_free(cli->notilist);
        cli->notilist = NULL;
 
+       if (cli->delay_notilist)
+               g_hash_table_destroy(cli->delay_notilist);
+
        if (cli->fd_id)
                g_source_remove(cli->fd_id);
 
+       if (cli->fd_out_id)
+               g_source_remove(cli->fd_out_id);
+
        if (cli->fd != -1)
                close(cli->fd);
 
index ddcb0ca..439c065 100644 (file)
@@ -38,11 +38,13 @@ struct bxt_daemon {
 struct bxt_client {
        int fd;
        guint fd_id;
+       guint fd_out_id;
 
        struct ucred cred;
        char *label;
 
        GList *notilist; /* struct bxt_noti */
+       GHashTable *delay_notilist;
 
        struct bxt_daemon *bxtd;
 };