diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2009-07-14 14:18:54 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2009-07-14 14:18:54 +0200 |
commit | 6baef17ecf1ed994cfc8038bc610e8b7ff88506a (patch) | |
tree | 60f9b74e148cf87cd014ffd6c3f885f7d6c2b185 | |
parent | 70670bf317a612a1700ffbd0dbc8d92614e0caf2 (diff) | |
download | bird-6baef17ecf1ed994cfc8038bc610e8b7ff88506a.tar bird-6baef17ecf1ed994cfc8038bc610e8b7ff88506a.zip |
Fixes bug in CLI TX buffer management.
-rw-r--r-- | nest/cli.c | 36 | ||||
-rw-r--r-- | nest/cli.h | 2 | ||||
-rw-r--r-- | sysdep/unix/main.c | 47 |
3 files changed, 55 insertions, 30 deletions
@@ -47,6 +47,20 @@ * The @this_cli variable points to a &cli structure of the session being * currently parsed, but it's of course available only in command handlers * not entered using the @cont hook. + * + * TX buffer management works as follows: At cli.tx_buf there is a + * list of TX buffers (struct cli_out), cli.tx_write is the buffer + * currently used by the producer (cli_printf(), cli_alloc_out()) and + * cli.tx_pos is the buffer currently used by the consumer + * (cli_write(), in system dependent code). The producer uses + * cli_out.wpos ptr as the current write position and the consumer + * uses cli_out.outpos ptr as the current read position. When the + * producer produces something, it calls cli_write_trigger(). If there + * is not enough space in the current buffer, the producer allocates + * the new one. When the consumer processes everything in the buffer + * queue, it calls cli_written(), tha frees all buffers (except the + * first one) and schedules cli.event . + * */ #include "nest/bird.h" @@ -196,6 +210,14 @@ cli_free_out(cli *c) c->async_msg_size = 0; } +void +cli_written(cli *c) +{ + cli_free_out(c); + ev_schedule(c->event); +} + + static byte *cli_rh_pos; static unsigned int cli_rh_len; static int cli_rh_trick_flag; @@ -263,11 +285,8 @@ cli_event(void *data) else cli_command(c); } - if (cli_write(c)) - { - cli_free_out(c); - ev_schedule(c->event); - } + + cli_write_trigger(c); } cli * @@ -296,13 +315,6 @@ cli_kick(cli *c) ev_schedule(c->event); } -void -cli_written(cli *c) -{ - cli_free_out(c); - ev_schedule(c->event); -} - static list cli_log_hooks; static int cli_log_inited; @@ -62,7 +62,7 @@ void cli_echo(unsigned int class, byte *msg); /* Functions provided by sysdep layer */ -int cli_write(cli *); +void cli_write_trigger(cli *); int cli_get_command(cli *); #endif diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 5f5b165..17845d2 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -178,22 +178,44 @@ cmd_reconfig(char *name, int type) static sock *cli_sk; static char *path_control_socket = PATH_CONTROL_SOCKET; -int + +static void cli_write(cli *c) { sock *s = c->priv; - if (c->tx_pos) + while (c->tx_pos) { struct cli_out *o = c->tx_pos; + + int len = o->wpos - o->outpos; s->tbuf = o->outpos; - if (sk_send(s, o->wpos - o->outpos) > 0) - { - c->tx_pos = o->next; - ev_schedule(c->event); - } + o->outpos = o->wpos; + + if (sk_send(s, len) <= 0) + return; + + c->tx_pos = o->next; } - return !c->tx_pos; + + /* Everything is written */ + s->tbuf = NULL; + cli_written(c); +} + +void +cli_write_trigger(cli *c) +{ + sock *s = c->priv; + + if (s->tbuf == NULL) + cli_write(c); +} + +static void +cli_tx(sock *s) +{ + cli_write(s->data); } int @@ -233,15 +255,6 @@ cli_rx(sock *s, int size UNUSED) } static void -cli_tx(sock *s) -{ - cli *c = s->data; - - if (cli_write(c)) - cli_written(c); -} - -static void cli_err(sock *s, int err) { if (config->cli_debug) |