Use two layers to cache server side response data to client.
1. A fixed-length ring buffer.
2. A list of free ring buffers and a list of empty full ring buffer.

If current ring buffer is full, put it into full buffer list and fetch
a free buffer frome free list.
---
 gatchat/gatserver.c |  106 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 98 insertions(+), 8 deletions(-)

diff --git a/gatchat/gatserver.c b/gatchat/gatserver.c
index bf7e847..6e76016 100644
--- a/gatchat/gatserver.c
+++ b/gatchat/gatserver.c
@@ -32,6 +32,15 @@
 #include "ringbuffer.h"
 #include "gatserver.h"
 
+#define MAX_BUFFER_NUM 5
+#define READ_BUF_SIZE 4096
+/* #define WRITE_SCHEDULER_DEBUG 1 */
+#ifdef WRITE_SCHEDULER_DEBUG
+#define WRITE_BUF_SIZE 4
+#else
+#define WRITE_BUF_SIZE 4096
+#endif
+
 enum ParserState {
        PARSER_STATE_IDLE,
        PARSER_STATE_A,
@@ -90,17 +99,50 @@ struct _GAtServer {
        struct v250_settings v250;              /* V.250 command setting */
        GIOChannel *channel;                    /* Server IO */
        guint read_watch;                       /* GSource read id, 0 if none */
+       guint write_watch;                      /* GSource write id, 0 if none 
*/
        guint read_so_far;                      /* Number of bytes processed */
        GAtDisconnectFunc user_disconnect;      /* User disconnect func */
        gpointer user_disconnect_data;          /* User disconnect data */
        GAtDebugFunc debugf;                    /* Debugging output function */
        gpointer debug_data;                    /* Data to pass to debug func */
        struct ring_buffer *read_buf;           /* Current read buffer */
+       struct ring_buffer *write_buf;          /* Current write buffer */
+       GSList *full_list;                      /* List of full ring buffer */
+       GSList *free_list;                      /* List of free ring buffer */
        guint max_read_attempts;                /* Max reads per select */
        enum ParserState parser_state;
        gboolean destroyed;                     /* Re-entrancy guard */
 };
 
+static void g_at_server_wakeup_writer(GAtServer *server);
+
+static gboolean alloc_free_list(GAtServer *server)
+{
+       struct ring_buffer *buf;
+       guint i;
+
+       for (i = 0; i < MAX_BUFFER_NUM; i++) {
+               buf = ring_buffer_new(WRITE_BUF_SIZE);
+               if (!buf)
+                       return FALSE;
+
+               server->free_list = g_slist_prepend(server->free_list, buf);
+       }
+
+       return TRUE;
+}
+
+static void send_common(GAtServer *server, const char *buf)
+{
+       gsize avail = ring_buffer_avail(server->write_buf);
+       gsize len = strlen(buf);
+
+       if (avail >= len)
+               ring_buffer_write(server->write_buf, buf, len);
+
+       g_at_server_wakeup_writer(server);
+}
+
 static void g_at_server_send_result(GAtServer *server, GAtServerResult result)
 {
        struct v250_settings v250 = server->v250;
@@ -108,7 +150,6 @@ static void g_at_server_send_result(GAtServer *server, 
GAtServerResult result)
        char buf[1024];
        char t = v250.s3;
        char r = v250.s4;
-       gsize wbuf;
 
        if (v250.quiet)
                return;
@@ -125,8 +166,7 @@ static void g_at_server_send_result(GAtServer *server, 
GAtServerResult result)
        g_at_util_debug_chat(FALSE, buf, strlen(buf),
                                server->debugf, server->debug_data);
 
-       g_io_channel_write(server->channel, (char *) buf, strlen(buf),
-                                                       &wbuf);
+       send_common(server, buf);
 }
 
 static inline gboolean is_at_command_prefix(const char c)
@@ -432,12 +472,30 @@ static gboolean received_data(GIOChannel *channel, 
GIOCondition cond,
        return TRUE;
 }
 
+static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
+                               gpointer data)
+{
+       return FALSE;
+}
+
 static void g_at_server_cleanup(GAtServer *server)
 {
        /* Cleanup all received data */
        ring_buffer_free(server->read_buf);
        server->read_buf = NULL;
 
+       /* Cleanup pending data to write */
+       ring_buffer_free(server->write_buf);
+       server->write_buf = NULL;
+
+       if (server->full_list)
+               g_slist_foreach(server->full_list, (GFunc)ring_buffer_free,
+                                       NULL);
+
+       if (server->free_list)
+               g_slist_foreach(server->free_list, (GFunc)ring_buffer_free,
+                                       NULL);
+
        server->channel = NULL;
 }
 
@@ -446,8 +504,6 @@ static void read_watcher_destroy_notify(GAtServer *server)
        g_at_server_cleanup(server);
        server->read_watch = 0;
 
-       server->channel = NULL;
-
        if (server->user_disconnect)
                server->user_disconnect(server->user_disconnect_data);
 
@@ -455,6 +511,23 @@ static void read_watcher_destroy_notify(GAtServer *server)
                g_free(server);
 }
 
+static void write_watcher_destroy_notify(GAtServer *server)
+{
+       server->write_watch = 0;
+}
+
+static void g_at_server_wakeup_writer(GAtServer *server)
+{
+       if (server->write_watch != 0)
+               return;
+
+       server->write_watch = g_io_add_watch_full(server->channel,
+                       G_PRIORITY_DEFAULT,
+                       G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                       can_write_data, server,
+                       (GDestroyNotify)write_watcher_destroy_notify);
+}
+
 static void v250_settings_create(struct v250_settings *v250)
 {
        v250->s3 = '\r';
@@ -482,12 +555,19 @@ GAtServer *g_at_server_new(GIOChannel *io)
        server->ref_count = 1;
        v250_settings_create(&server->v250);
        server->channel = io;
-       server->read_buf = ring_buffer_new(4096);
-       server->max_read_attempts = 3;
-
+       server->read_buf = ring_buffer_new(READ_BUF_SIZE);
        if (!server->read_buf)
                goto error;
 
+       server->write_buf = ring_buffer_new(WRITE_BUF_SIZE);
+       if (!server->write_buf)
+               goto error;
+
+       if (!alloc_free_list(server))
+               goto error;
+
+       server->max_read_attempts = 3;
+
        if (!g_at_util_setup_io(server->channel, G_IO_FLAG_NONBLOCK))
                goto error;
 
@@ -502,6 +582,13 @@ error:
        if (server->read_buf)
                ring_buffer_free(server->read_buf);
 
+       if (server->write_buf)
+               ring_buffer_free(server->write_buf);
+
+       if (server->free_list)
+               g_slist_foreach(server->free_list, (GFunc)ring_buffer_free,
+                                       NULL);
+
        if (server)
                g_free(server);
 
@@ -552,6 +639,9 @@ gboolean g_at_server_shutdown(GAtServer *server)
        server->user_disconnect = NULL;
        server->user_disconnect_data = NULL;
 
+       if (server->write_watch)
+               g_source_remove(server->write_watch);
+
        if (server->read_watch)
                g_source_remove(server->read_watch);
 
-- 
1.6.6.1

_______________________________________________
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono

Reply via email to