* Zhenhua Zhang <[email protected]> [2010-02-10 16:13:40 +0800]:

> 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 |  111 +++++++++++++++++++++++++++++++++++++++++++++++---
>  1 files changed, 104 insertions(+), 7 deletions(-)
> 
> diff --git a/gatchat/gatserver.c b/gatchat/gatserver.c
> index bf7e847..6b40084 100644
> --- a/gatchat/gatserver.c
> +++ b/gatchat/gatserver.c
> @@ -32,6 +32,9 @@
>  #include "ringbuffer.h"
>  #include "gatserver.h"
>  
> +#define MAX_BUFFER_NUM 5
> +/* #define WRITE_SCHEDULER_DEBUG 1 */
> +
>  enum ParserState {
>       PARSER_STATE_IDLE,
>       PARSER_STATE_A,
> @@ -90,17 +93,54 @@ 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++) {
> +#ifdef WRITE_SCHEDULER_DEBUG
> +             buf = ring_buffer_new(4);
> +#else
> +             buf = ring_buffer_new(4096);
> +#endif

Why not a macro to define buf size? So you don't need to use ifdef
everytime

#ifdef WRITE_SCHEDULER_DEBUG
                BUF_SIZE = 4
#else
                BUF_SIZE = 4096 
#endif

> +             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 +148,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 +164,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 +470,35 @@ 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 free_ring_buffer(struct ring_buffer *buf)
> +{
> +     ring_buffer_free(buf);
> +}

This seems pointless to me.

> +
>  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)free_ring_buffer,
> +                                     NULL);
> +
> +     if (server->free_list)
> +             g_slist_foreach(server->free_list, (GFunc)free_ring_buffer,
> +                                     NULL);
> +
>       server->channel = NULL;
>  }
>  
> @@ -446,8 +507,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 +514,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';
> @@ -483,11 +559,22 @@ GAtServer *g_at_server_new(GIOChannel *io)
>       v250_settings_create(&server->v250);
>       server->channel = io;
>       server->read_buf = ring_buffer_new(4096);
> -     server->max_read_attempts = 3;
> -
>       if (!server->read_buf)
>               goto error;
>  
> +#ifdef WRITE_SCHEDULER_DEBUG
> +     server->write_buf = ring_buffer_new(4);
> +#else
> +     server->write_buf = ring_buffer_new(4096);
> +#endif
> +     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 +589,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)free_ring_buffer,
> +                                     NULL);
> +
>       if (server)
>               g_free(server);
>  
> @@ -552,6 +646,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
> [email protected]
> http://lists.ofono.org/listinfo/ofono

-- 
Gustavo F. Padovan
http://padovan.org

ProFUSION embedded systems - http://profusion.mobi
_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to