summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/command.c7
-rw-r--r--lib/command.h3
-rw-r--r--lib/command_parse.h1
-rw-r--r--lib/command_queue.c2
-rw-r--r--lib/distribute.c13
-rw-r--r--lib/elstring.c2
-rw-r--r--lib/errno_names.c2
-rw-r--r--lib/getopt.c4
-rw-r--r--lib/getopt1.c4
-rw-r--r--lib/hash.c11
-rw-r--r--lib/hash.h2
-rw-r--r--lib/if.c18
-rw-r--r--lib/if.h1
-rw-r--r--lib/if_rmap.c9
-rw-r--r--lib/keystroke.c12
-rw-r--r--lib/list_util.c2
-rw-r--r--lib/log.c11
-rw-r--r--lib/log.h1
-rw-r--r--lib/memory.c25
-rw-r--r--lib/memory.h2
-rw-r--r--lib/misc.h22
-rw-r--r--lib/mqueue.c4
-rw-r--r--lib/network.c2
-rw-r--r--lib/prefix.c13
-rw-r--r--lib/prefix.h4
-rw-r--r--lib/privs.c1
-rw-r--r--lib/pthread_safe.c81
-rw-r--r--lib/pthread_safe.h12
-rw-r--r--lib/qfstring.c311
-rw-r--r--lib/qfstring.h112
-rw-r--r--lib/qiovec.c3
-rw-r--r--lib/qlib_init.c2
-rw-r--r--lib/qpath.c2
-rw-r--r--lib/qpthreads.h2
-rw-r--r--lib/qrand.c2
-rw-r--r--lib/qstring.c2
-rw-r--r--lib/qtime.c104
-rw-r--r--lib/qtime.h28
-rw-r--r--lib/qtimers.c5
-rw-r--r--lib/regex.c51
-rw-r--r--lib/sockopt.c9
-rw-r--r--lib/sockunion.c1
-rw-r--r--lib/stream.c2
-rw-r--r--lib/table.c14
-rw-r--r--lib/thread.c153
-rw-r--r--lib/thread.h3
-rw-r--r--lib/vector.c2
-rw-r--r--lib/vio_fifo.c1683
-rw-r--r--lib/vio_fifo.h172
-rw-r--r--lib/vio_lines.c1
-rw-r--r--lib/vty.c1
-rw-r--r--lib/vty_cli.c12
-rw-r--r--lib/vty_command.c8
-rw-r--r--lib/vty_io.c17
-rw-r--r--lib/vty_io_basic.c2
-rw-r--r--lib/vty_io_file.c8
-rw-r--r--lib/vty_io_term.c12
-rw-r--r--lib/vty_log.c2
-rw-r--r--lib/workqueue.c31
-rw-r--r--lib/workqueue.h2
-rw-r--r--lib/zassert.h2
-rw-r--r--lib/zclient.c6
-rw-r--r--lib/zclient.h9
-rw-r--r--lib/zconfig.h12
-rw-r--r--lib/zebra.h2
65 files changed, 1568 insertions, 1493 deletions
diff --git a/lib/command.c b/lib/command.c
index 61f554bb..1fc85344 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -21,10 +21,8 @@ along with GNU Zebra; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include "zconfig.h"
-#include "version.h"
-
#include "misc.h"
+#include "version.h"
#include <ctype.h>
#include <sys/param.h>
@@ -58,7 +56,7 @@ vector node_vector = NULL ;
/*==============================================================================
* Default motd string.
*/
-const char* default_motd =
+static const char* default_motd =
"\n"
"Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ")\n"
QUAGGA_COPYRIGHT "\n"
@@ -2287,6 +2285,7 @@ cmd_init (bool terminal)
install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
install_element (VIEW_NODE, &show_thread_cpu_cmd);
install_element (ENABLE_NODE, &show_thread_cpu_cmd);
+ install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
install_element (VIEW_NODE, &show_work_queues_cmd);
install_element (ENABLE_NODE, &show_work_queues_cmd);
} ;
diff --git a/lib/command.h b/lib/command.h
index 2b835cc8..3ad758d5 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -59,6 +59,9 @@
.r_doc = NULL, \
} ;
+/* Legacy name for cmd_command */
+#define cmd_element cmd_command
+
#define DEFUN_CMD_FUNC_DECL(funcname) \
static cmd_function funcname;
diff --git a/lib/command_parse.h b/lib/command_parse.h
index a1e801ce..5f17d083 100644
--- a/lib/command_parse.h
+++ b/lib/command_parse.h
@@ -24,7 +24,6 @@
#ifndef _ZEBRA_COMMAND_PARSE_H
#define _ZEBRA_COMMAND_PARSE_H
-#include "zconfig.h" /* HAVE_IPV6 */
#include "misc.h"
#include "command_common.h"
diff --git a/lib/command_queue.c b/lib/command_queue.c
index f83e3291..7946d0e8 100644
--- a/lib/command_queue.c
+++ b/lib/command_queue.c
@@ -18,8 +18,6 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
-
-#include "zconfig.h" /* for CONSUMED_TIME_CHECK */
#include "misc.h"
#include "qpnexus.h"
diff --git a/lib/distribute.c b/lib/distribute.c
index 0e1c9458..8c0f057e 100644
--- a/lib/distribute.c
+++ b/lib/distribute.c
@@ -115,16 +115,11 @@ distribute_get (const char *ifname)
}
static unsigned int
-distribute_hash_make (struct distribute *dist)
+distribute_hash_make (void *arg)
{
- unsigned int i, key;
+ const struct distribute *dist = arg;
- key = 0;
- if (dist->ifname)
- for (i = 0; i < strlen (dist->ifname); i++)
- key += dist->ifname[i];
-
- return key;
+ return dist->ifname ? string_hash_make (dist->ifname) : 0;
}
/* If two distribute-list have same value then return 1 else return
@@ -764,7 +759,7 @@ distribute_list_reset ()
void
distribute_list_init (int node)
{
- disthash = hash_create ((unsigned int (*) (void *)) distribute_hash_make,
+ disthash = hash_create (distribute_hash_make,
(int (*) (const void *, const void *)) distribute_cmp);
if(node==RIP_NODE) {
diff --git a/lib/elstring.c b/lib/elstring.c
index 41fc88ed..64756a64 100644
--- a/lib/elstring.c
+++ b/lib/elstring.c
@@ -18,7 +18,7 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
-
+#include "misc.h"
#include <ctype.h>
#include "elstring.h"
diff --git a/lib/errno_names.c b/lib/errno_names.c
index 7238f1a7..3c1ff23c 100644
--- a/lib/errno_names.c
+++ b/lib/errno_names.c
@@ -18,8 +18,8 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+#include "misc.h"
-#include <stddef.h>
#include <errno.h>
#include <netdb.h>
diff --git a/lib/getopt.c b/lib/getopt.c
index ec98feac..75cf7c8b 100644
--- a/lib/getopt.c
+++ b/lib/getopt.c
@@ -30,10 +30,6 @@
# define _NO_PROTO
#endif
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include "zebra.h"
#include <stdio.h>
diff --git a/lib/getopt1.c b/lib/getopt1.c
index dc36fd0e..d5514c33 100644
--- a/lib/getopt1.c
+++ b/lib/getopt1.c
@@ -20,10 +20,6 @@
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
USA. */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
#include "zebra.h"
#include "getopt.h"
diff --git a/lib/hash.c b/lib/hash.c
index 672327ec..6db79ea7 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -101,6 +101,17 @@ hash_lookup (struct hash *hash, void *data)
return hash_get (hash, data, NULL);
}
+/* Simple Bernstein hash which is simple and fast for common case */
+unsigned int string_hash_make (const char *str)
+{
+ unsigned int hash = 0;
+
+ while (*str)
+ hash = (hash * 33) ^ (unsigned int) *str++;
+
+ return hash;
+}
+
/* This function release registered value from specified hash. When
release is successfully finished, return the data pointer in the
hash backet. */
diff --git a/lib/hash.h b/lib/hash.h
index f4b1c23e..4cb772e5 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -70,4 +70,6 @@ extern void hash_iterate (struct hash *,
extern void hash_clean (struct hash *, void (*) (void *));
extern void hash_free (struct hash *);
+extern unsigned int string_hash_make (const char *);
+
#endif /* _ZEBRA_HASH_H */
diff --git a/lib/if.c b/lib/if.c
index 21427e71..23d35054 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -879,3 +879,21 @@ if_init (void)
memset (&if_master, 0, sizeof if_master);
}
+
+void
+if_terminate (void)
+{
+ for (;;)
+ {
+ struct interface *ifp;
+
+ ifp = listnode_head (iflist);
+ if (ifp == NULL)
+ break;
+
+ if_delete (ifp);
+ }
+
+ list_delete (iflist);
+ iflist = NULL;
+}
diff --git a/lib/if.h b/lib/if.h
index b4b83cd5..f89f488b 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -266,6 +266,7 @@ extern int if_is_pointopoint (struct interface *);
extern int if_is_multicast (struct interface *);
extern void if_add_hook (int, int (*)(struct interface *));
extern void if_init (void);
+extern void if_terminate (void);
extern void if_dump_all (void);
extern const char *if_flag_dump(unsigned long);
diff --git a/lib/if_rmap.c b/lib/if_rmap.c
index 9ef5ed94..e51f1fe5 100644
--- a/lib/if_rmap.c
+++ b/lib/if_rmap.c
@@ -110,14 +110,9 @@ if_rmap_get (const char *ifname)
static unsigned int
if_rmap_hash_make (void *data)
{
- struct if_rmap *if_rmap = data;
- unsigned int i, key;
+ const struct if_rmap *if_rmap = data;
- key = 0;
- for (i = 0; i < strlen (if_rmap->ifname); i++)
- key += if_rmap->ifname[i];
-
- return key;
+ return string_hash_make (if_rmap->ifname);
}
static int
diff --git a/lib/keystroke.c b/lib/keystroke.c
index 8325b8f8..2b5d8128 100644
--- a/lib/keystroke.c
+++ b/lib/keystroke.c
@@ -19,8 +19,7 @@
* Boston, MA 02111-1307, USA.
*/
-#include <stdbool.h>
-#include <string.h>
+#include "misc.h"
#include "keystroke.h"
@@ -28,7 +27,6 @@
#include "memory.h"
#include "mqueue.h"
-#include "zassert.h"
/*==============================================================================
*/
@@ -274,7 +272,7 @@ typedef struct keystroke_state keystroke_state_t ;
struct keystroke_stream
{
- vio_fifo_t fifo ; /* the keystrokes -- embedded */
+ vio_fifo fifo ; /* the keystrokes */
keystroke_callback* iac_callback ;
void* iac_callback_context ;
@@ -373,7 +371,7 @@ keystroke_stream_new(uint8_t csi_char, keystroke_callback* iac_callback,
stream->iac_callback = iac_callback ;
stream->iac_callback_context = iac_callback_context ;
- vio_fifo_init_new(stream->fifo, keystroke_buffer_len) ;
+ stream->fifo = vio_fifo_new(keystroke_buffer_len) ;
stream->CSI = (csi_char != '\0') ? csi_char : 0x1B ;
@@ -390,7 +388,7 @@ keystroke_stream_free(keystroke_stream stream)
{
if (stream != NULL)
{
- vio_fifo_reset(stream->fifo, keep_it) ;
+ stream->fifo = vio_fifo_free(stream->fifo) ;
XFREE(MTYPE_KEY_STREAM, stream) ;
} ;
@@ -446,7 +444,7 @@ keystroke_stream_eof(keystroke_stream stream)
extern void
keystroke_stream_set_eof(keystroke_stream stream, bool timed_out)
{
- vio_fifo_reset(stream->fifo, keep_it) ;
+ vio_fifo_clear(stream->fifo, true) ; /* and clear marks */
stream->eof_met = true ; /* essential information */
stream->timed_out = timed_out ; /* variant of eof */
diff --git a/lib/list_util.c b/lib/list_util.c
index f73244a4..0f7e8a02 100644
--- a/lib/list_util.c
+++ b/lib/list_util.c
@@ -18,7 +18,7 @@
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
-
+#include "misc.h"
#include "list_util.h"
/*==============================================================================
diff --git a/lib/log.c b/lib/log.c
index e3296d3a..d78c795e 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -306,6 +306,8 @@ zlog (struct zlog *zl, int priority, const char *format, ...)
/*------------------------------------------------------------------------------
* Preparation of line to send to logging: file, stdout or "monitor" terminals.
+ *
+ * Line ends in '\n', but no terminating '\0'.
*/
static void
uvzlog_line(logline ll, struct zlog *zl, int priority,
@@ -314,7 +316,7 @@ uvzlog_line(logline ll, struct zlog *zl, int priority,
const char* q ;
qf_str_t qfs ;
- qfs_init(qfs, ll->line, sizeof(ll->line) - 1) ; /* leave space for '\n' */
+ qfs_init(qfs, ll->line, sizeof(ll->line)) ;
/* "<time stamp>" */
uquagga_timestamp(qfs, (zl != NULL) ? zl->timestamp_precision : 0) ;
@@ -339,8 +341,13 @@ uvzlog_line(logline ll, struct zlog *zl, int priority,
/* Now the log line itself (uses a *copy* of the va_list) */
qfs_vprintf(qfs, format, va) ;
- /* Set pointer to where the '\n' is going */
+ /* Stick '\n' on the end */
qfs_append_n(qfs, "\n", 1) ;
+
+ /* Worry about overflow of message */
+ if (qfs_overflow(qfs) != 0)
+ qfs_term_string(qfs, "...\n", sizeof("...\n") - 1) ;
+
ll->len = qfs_len(qfs) ;
} ;
diff --git a/lib/log.h b/lib/log.h
index cf5bc9ec..30a81a28 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -25,7 +25,6 @@
#ifndef _ZEBRA_LOG_H
#define _ZEBRA_LOG_H
-#include "zconfig.h"
#include "misc.h"
#include <signal.h>
#include <syslog.h>
diff --git a/lib/memory.c b/lib/memory.c
index d96ff21d..10e107a3 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -115,6 +115,12 @@ zerror (const char *fname, int type, size_t size)
/*------------------------------------------------------------------------------
* Memory allocation.
+ *
+ * Allocate memory of a given size, to be tracked by a given type.
+ *
+ * Returns: pointer to usable memory.
+ *
+ * NB: If memory cannot be allocated, aborts execution.
*/
void *
zmalloc (enum MTYPE mtype, size_t size MEMORY_TRACKER_NAME)
@@ -173,7 +179,15 @@ zcalloc (enum MTYPE mtype, size_t size MEMORY_TRACKER_NAME)
/*------------------------------------------------------------------------------
* Memory reallocation.
*
- * NB: just like real realloc(), is same as malloc() if ptr == NULL.
+ * Given a pointer returned by zmalloc()/zcalloc()/zrealloc(), extend or
+ * contract the allocation to the given size -- retaining current type.
+ * The type given MUST be the original type.
+ *
+ * Given a NULL, allocate memory as zmalloc().
+ *
+ * Returns: pointer to usable memory.
+ *
+ * NB: If memory cannot be allocated, aborts execution.
*/
void *
zrealloc (enum MTYPE mtype, void *ptr, size_t size MEMORY_TRACKER_NAME)
@@ -203,7 +217,10 @@ zrealloc (enum MTYPE mtype, void *ptr, size_t size MEMORY_TRACKER_NAME)
/*------------------------------------------------------------------------------
* Memory free.
*
- * NB: just like real free(), does nothing if ptr == NULL.
+ * Free memory allocated by zmalloc()/zcalloc()/zrealloc()/zstrdup().
+ * The type given MUST be the original type.
+ *
+ * Does nothing if the given pointer is NULL.
*/
void
zfree (enum MTYPE mtype, void *ptr)
@@ -226,6 +243,10 @@ zfree (enum MTYPE mtype, void *ptr)
/*------------------------------------------------------------------------------
* String duplication.
+ *
+ * Memory is allocated as zmalloc() and must later be freed by zfree().
+ *
+ * NB: If memory cannot be allocated, aborts execution.
*/
char *
zstrdup (enum MTYPE mtype, const char *str MEMORY_TRACKER_NAME)
diff --git a/lib/memory.h b/lib/memory.h
index 0585307b..265a8226 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -30,7 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
*
* The file memtypes.c contains a number of arrays of struct memory_list, which
* map memory type names to a string, for printing. Those arrays are
- * collected together in an array of struvt mlist.
+ * collected together in an array of struct mlist.
*/
struct memory_list /* one per memory type */
{
diff --git a/lib/misc.h b/lib/misc.h
index 1c53f2e2..f5f9d9f6 100644
--- a/lib/misc.h
+++ b/lib/misc.h
@@ -22,17 +22,37 @@
#ifndef _ZEBRA_MISC_H
#define _ZEBRA_MISC_H
+/* "zconfig.h" is included at the start of this "misc.h", and at the start
+ * of "zebra.h". This ensures that we get <features.h> defined early, so
+ * that all other #includes get the same set of features.
+ */
+
#include "zconfig.h"
+/* This is horrible... but for some purposes wish to turn *off* __USE_GNU.
+ *
+ * e.g: to persuade <string.h> to give POSIX version of strerror_r !!!
+ */
+#ifdef NO_USE_GNU
+# undef NO_USE_GNU
+# ifdef __USE_GNU
+# define NO_USE_GNU 1
+# undef __USE_GNU
+# endif
+#endif
+
/* Stuff which we generally expect to have */
-#include <limits.h>
+
#include <string.h>
+#include <limits.h>
+#include <unistd.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
+#include "confirm.h"
#include "zassert.h"
/* Bit number to bit mask */
diff --git a/lib/mqueue.c b/lib/mqueue.c
index 8cef1ad9..f816932b 100644
--- a/lib/mqueue.c
+++ b/lib/mqueue.c
@@ -18,12 +18,10 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
-
-#include <string.h>
+#include "misc.h"
#include "memory.h"
#include "mqueue.h"
-#include "zassert.h"
/*==============================================================================
* These message queues are designed for inter-qpthread communication.
diff --git a/lib/network.c b/lib/network.c
index 57cca0d4..6f12805a 100644
--- a/lib/network.c
+++ b/lib/network.c
@@ -20,8 +20,6 @@
* 02111-1307, USA.
*/
-//#include <zebra.h>
-
#include "misc.h"
#include "qdebug_nb.h"
diff --git a/lib/prefix.c b/lib/prefix.c
index 8774475a..d511a535 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -42,7 +42,7 @@ static const u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,
/* Address Famiy Identifier to Address Family converter. */
int
-afi2family (int afi)
+afi2family (afi_t afi)
{
if (afi == AFI_IP)
return AF_INET;
@@ -53,7 +53,7 @@ afi2family (int afi)
return 0;
}
-int
+afi_t
family2afi (int family)
{
if (family == AF_INET)
@@ -71,15 +71,16 @@ prefix_match (const struct prefix *n, const struct prefix *p)
{
int offset;
int shift;
-
- /* Set both prefix's head pointer. */
- const u_char *np = (const u_char *)&n->u.prefix;
- const u_char *pp = (const u_char *)&p->u.prefix;
+ const u_char *np, *pp;
/* If n's prefix is longer than p's one return 0. */
if (n->prefixlen > p->prefixlen)
return 0;
+ /* Set both prefix's head pointer. */
+ np = (const u_char *)&n->u.prefix;
+ pp = (const u_char *)&p->u.prefix;
+
offset = n->prefixlen / PNBBY;
shift = n->prefixlen % PNBBY;
diff --git a/lib/prefix.h b/lib/prefix.h
index d8ed9a8a..bc44244c 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -147,8 +147,8 @@ prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen)
}
/* Prototypes. */
-extern int afi2family (int);
-extern int family2afi (int);
+extern int afi2family (afi_t);
+extern afi_t family2afi (int);
extern struct prefix *prefix_new (void);
extern void prefix_free (struct prefix *);
diff --git a/lib/privs.c b/lib/privs.c
index bcee6228..46dc0977 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -22,7 +22,6 @@
* 02111-1307, USA.
*/
#include "zebra.h"
-#include "zconfig.h"
#include "log.h"
#include "privs.h"
#include "memory.h"
diff --git a/lib/pthread_safe.c b/lib/pthread_safe.c
index 828b8e29..4a698216 100644
--- a/lib/pthread_safe.c
+++ b/lib/pthread_safe.c
@@ -25,6 +25,12 @@
* safe_ function is called on the same thread
*/
+/* Need "NO_USE_GNU" to turn off __USE_GNU in "misc.h" in order to get the
+ * POSIX version of strerror_r() :-(
+ */
+#define NO_USE_GNU
+
+#include "misc.h"
#include "pthread_safe.h"
#include "qpthreads.h"
#include "memory.h"
@@ -48,6 +54,8 @@ static char * thread_buff(void);
static pthread_key_t tsd_key;
static const int buff_size = 1024;
+static const char ellipsis[] = "..." ;
+
/* Module initialization, before any threads have been created */
void
safe_init_r(void)
@@ -134,7 +142,7 @@ safe_strerror(int errnum)
* to show this has happened.
*/
-static void errtox(strerror_t* st, int err, int len, int want) ;
+static void errtox(strerror_t* st, int err, uint len, uint want) ;
/*------------------------------------------------------------------------------
* Construct string to describe the given error of the form:
@@ -144,7 +152,7 @@ static void errtox(strerror_t* st, int err, int len, int want) ;
* Thread safe extension to strerror. Never returns NULL.
*/
extern strerror_t
-errtoa(int err, int len)
+errtoa(int err, uint len)
{
strerror_t st ;
@@ -159,7 +167,7 @@ errtoa(int err, int len)
* Thread-safe. Never returns NULL.
*/
extern strerror_t
-errtoname(int err, int len)
+errtoname(int err, uint len)
{
strerror_t st ;
@@ -174,7 +182,7 @@ errtoname(int err, int len)
* Thread safe replacement for strerror. Never returns NULL.
*/
extern strerror_t
-errtostr(int err, int len)
+errtostr(int err, uint len)
{
strerror_t st ;
@@ -189,21 +197,23 @@ errtostr(int err, int len)
* want == 1 -- return just name
* want == 2 -- return just the strerror()
* want == 3 -- return both, with the strerror() in single quotes.
+ *
+ * NB: this is not async-signal-safe !
*/
static void
-errtox(strerror_t* st, int err, int len, int want)
+errtox(strerror_t* st, int err, uint len, uint want)
{
qf_str_t qfs ;
const char* q ;
- int ql ;
+ uint ql ;
/* Prepare. */
int errno_saved = errno ;
- if ((len <= 0) || (len >= (int)sizeof(st->str)))
- len = sizeof(st->str) - 1 ;
- qfs_init(qfs, st->str, len + 1) ;
+ if ((len <= 0) || (len >= sizeof(st->str)))
+ len = sizeof(st->str) ;
+ qfs_init(qfs, st->str, len) ;
q = "" ;
ql = 0 ;
@@ -293,15 +303,20 @@ errtox(strerror_t* st, int err, int len, int want)
} ;
} ;
- /* Add strerror to the result... looking out for overflow. */
- len = strlen(errm) ;
+ /* Add strerror to the result... with quotes as rquired */
+ if (ql != 0)
+ qfs_append(qfs, q) ;
- if ((len + ql) <= qfs_left(qfs)) /* accounting for "quotes" */
- qfs_printf(qfs, "%s%s%s", q, errm, q) ;
- else
- qfs_printf(qfs, "%s%.*s...%s",
- q, (int)(qfs_left(qfs) - ql - 3), errm, q) ;
- /* -ve precision is ignored ! */
+ qfs_append(qfs, errm) ;
+
+ if (ql != 0)
+ qfs_append(qfs, q) ;
+
+ /* '\0' terminate -- if has overflowed, replace last few characters
+ * by "..." -- noting that sizeof("...") includes the '\0'.
+ */
+ if (qfs_term(qfs) != 0)
+ qfs_term_string(qfs, ellipsis, sizeof(ellipsis)) ;
} ;
/* Put back errno */
@@ -341,7 +356,7 @@ errtox(strerror_t* st, int err, int len, int want)
* error.
*/
-static void eaitox(strerror_t* st, int eai, int err, int len, int want) ;
+static void eaitox(strerror_t* st, int eai, int err, uint len, uint want) ;
/*------------------------------------------------------------------------------
* Construct string to describe the given EAI_XXX error of the form:
@@ -352,7 +367,7 @@ static void eaitox(strerror_t* st, int eai, int err, int len, int want) ;
* Thread safe. Never returns NULL.
*/
extern strerror_t
-eaitoa(int eai, int err, int len)
+eaitoa(int eai, int err, uint len)
{
strerror_t st ;
@@ -369,7 +384,7 @@ eaitoa(int eai, int err, int len)
* Thread-safe. Never returns NULL.
*/
extern strerror_t
-eaitoname(int eai, int err, int len)
+eaitoname(int eai, int err, uint len)
{
strerror_t st ;
@@ -386,7 +401,7 @@ eaitoname(int eai, int err, int len)
* Thread-safe. Never returns NULL.
*/
extern strerror_t
-eaitostr(int eai, int err, int len)
+eaitostr(int eai, int err, uint len)
{
strerror_t st ;
@@ -405,12 +420,12 @@ eaitostr(int eai, int err, int len)
* err != 0 => if EAI_SYSTEM, return result for errno == err instead.
*/
static void
-eaitox(strerror_t* st, int eai, int err, int len, int want)
+eaitox(strerror_t* st, int eai, int err, uint len, uint want)
{
qf_str_t qfs ;
const char* q ;
- int ql ;
+ uint ql ;
/* Look out for mapping EAI_SYSTEM */
if ((eai == EAI_SYSTEM) && (err != 0))
@@ -455,14 +470,20 @@ eaitox(strerror_t* st, int eai, int err, int len, int want)
else
eaim = gai_strerror(eai) ;
- /* Add strerror to the result... looking out for overflow. */
- len = strlen(eaim) ;
+ /* Add strerror to the result... with quotes as rquired */
+ if (ql != 0)
+ qfs_append(qfs, q) ;
- if ((len + ql) <= qfs_left(qfs)) /* accounting for "quotes" */
- qfs_printf(qfs, "%s%s%s", q, eaim, q) ;
- else
- qfs_printf(qfs, "%s%.*s...%s", q, qfs_left(qfs) - ql - 3, eaim, q) ;
- /* -ve precision is ignored ! */
+ qfs_append(qfs, eaim) ;
+
+ if (ql != 0)
+ qfs_append(qfs, q) ;
+
+ /* '\0' terminate -- if has overflowed, replace last few characters
+ * by "..." -- noting that sizeof("...") includes the '\0'.
+ */
+ if (qfs_term(qfs) != 0)
+ qfs_term_string(qfs, ellipsis, sizeof(ellipsis)) ;
} ;
/* Put back errno */
diff --git a/lib/pthread_safe.h b/lib/pthread_safe.h
index 9518f3d1..b7faba1a 100644
--- a/lib/pthread_safe.h
+++ b/lib/pthread_safe.h
@@ -35,12 +35,12 @@ extern void safe_finish(void);
extern const char * safe_strerror(int errnum);
extern const char * safe_inet_ntoa (struct in_addr in);
-extern strerror_t errtoa(int err, int len) ;
-extern strerror_t errtoname(int err, int len) ;
-extern strerror_t errtostr(int err, int len) ;
+extern strerror_t errtoa(int err, uint len) ;
+extern strerror_t errtoname(int err, uint len) ;
+extern strerror_t errtostr(int err, uint len) ;
-extern strerror_t eaitoa(int eai, int err, int len) ;
-extern strerror_t eaitoname(int eai, int err, int len) ;
-extern strerror_t eaitostr(int eai, int err, int len) ;
+extern strerror_t eaitoa(int eai, int err, uint len) ;
+extern strerror_t eaitoname(int eai, int err, uint len) ;
+extern strerror_t eaitostr(int eai, int err, uint len) ;
#endif /* PTHREAD_SAFE_H_ */
diff --git a/lib/qfstring.c b/lib/qfstring.c
index 3639bccb..25558797 100644
--- a/lib/qfstring.c
+++ b/lib/qfstring.c
@@ -18,57 +18,100 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+#include "misc.h"
#include "qfstring.h"
-#include "zassert.h"
/*==============================================================================
*/
/*------------------------------------------------------------------------------
- * Initialise qf_str -- to given size (which includes the '\0')
+ * Initialise qf_str -- to given size, zero offset and zero overflow.
*
- * Sets pointers and terminates an empty string with one byte reserved for the
- * terminating '\0'.
+ * Note that does not terminate the string -- that must be done separately.
*
* This operation is async-signal-safe.
*/
extern void
-qfs_init(qf_str qfs, char* str, size_t size)
+qfs_init(qf_str qfs, char* str, uint size)
{
- assert(size > 0) ;
+ qfs->str = str ;
+ qfs->ptr = str ;
+ qfs->end = str + size ;
+ qfs->offset = 0 ;
+ qfs->overflow = 0 ;
+} ;
- qfs->str = str ;
- qfs->end = str + size - 1 ;
+/*------------------------------------------------------------------------------
+ * Initialise qf_str -- to given size, with given offset and zero overflow.
+ *
+ * Note that does not terminate the string -- that must be done separately.
+ *
+ * This operation is async-signal-safe.
+ */
+extern void
+qfs_init_offset(qf_str qfs, char* str, uint size, uint offset)
+{
+ qfs->str = str ;
+ qfs->ptr = str ;
+ qfs->end = str + size ;
+ qfs->offset = offset ;
+ qfs->overflow = 0 ;
+} ;
- *str = '\0' ;
- qfs->ptr = str ;
+/*------------------------------------------------------------------------------
+ * Reset given qf_str -- with the given offset and zero overflow.
+ *
+ * Sets ptr back to the start of the string and set the given offset.
+ *
+ * This operation is async-signal-safe.
+ */
+extern void
+qfs_reset_offset(qf_str qfs, uint offset)
+{
+ qfs->ptr = qfs->str ;
+ qfs->offset = offset ;
+ qfs->overflow = 0 ;
} ;
/*------------------------------------------------------------------------------
- * Initialise qf_str which already contains string -- to given size (which
- * includes the '\0')
+ * Initialise qf_str which already contains string -- to given size with zero
+ * overflow.
*
* This may be used to prepare for appending to a buffer which already contains
* something.
*
- * Sets pointers, setting the write pointer to the existing terminating '\0'.
+ * Sets pointers, setting the write pointer to the existing '\0'.
*
* This operation is async-signal-safe.
+ *
+ * NB: it is a mistake if the size given is less than the length of the
+ * string (excluding the trailing '\0').
*/
extern void
-qfs_init_as_is(qf_str qfs, char* str, size_t size)
+qfs_init_as_is(qf_str qfs, char* str, uint size)
{
assert(size > 0) ;
- qfs->str = str ;
- qfs->end = str + size - 1 ;
+ qfs->str = str ;
+ qfs->end = str + size ;
+ qfs->offset = 0 ;
+ qfs->overflow = 0 ;
+
+ while (*str != '\0')
+ ++str ;
- qfs->ptr = strchr(str, '\0') ;
+ qfs->ptr = str ; /* point at '\0' */
+
+ assert(qfs->ptr <= qfs->end) ;
} ;
/*------------------------------------------------------------------------------
- * Terminate string with the given string.
+ * Terminate string with the given string if given length (which may include
+ * a '\0').
+ *
+ * This is for when the qstring has overflowed, and wish to indicate that at
+ * the end -- so takes no notice of offset.
*
* If necessary, characters are discarded from the end of the string in order
* to fit in the terminating stuff.
@@ -80,34 +123,25 @@ qfs_init_as_is(qf_str qfs, char* str, size_t size)
* This operation is async-signal-safe.
*/
extern void
-qfs_term(qf_str qfs, const char* src)
+qfs_term_string(qf_str qfs, const char* src, uint n)
{
- int len ;
- int excess ;
+ uint h ;
- if ((src == NULL) || (*src == '\0'))
- {
- *qfs->ptr = '\0' ; /* should be true anyway */
- return ;
- } ;
+ h = qfs->end - qfs->ptr ; /* space available */
- len = strlen(src) ;
- excess = qfs_len(qfs) - len ;
- if (excess > 0)
+ if (h < n)
{
- if (excess <= (qfs->ptr - qfs->str))
- qfs->ptr -= excess ;
- else
+ h = qfs->end - qfs->str ; /* total space */
+ if (h < n)
{
- int want = len ;
- len = qfs->end - qfs->str ; /* take what can... */
- src += (want - len) ; /* ... from the end */
- qfs->ptr = qfs->str ;
+ src += n - h ; /* past what will not fit */
+ n = h ;
} ;
+ qfs->ptr = qfs->end - n ;
} ;
- memcpy(qfs->ptr, src, len + 1) ; /* include the '\0' */
- qfs->ptr += len ;
+ while (n--)
+ *qfs->ptr++ = *src++ ;
} ;
/*==============================================================================
@@ -119,26 +153,29 @@ qfs_term(qf_str qfs, const char* src)
*
* May append nothing at all !
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
extern void
qfs_append(qf_str qfs, const char* src)
{
- int n ;
-
- if ((src == NULL) || (*src == '\0'))
+ if (src == NULL)
return ;
- n = strlen(src) ;
-
- if (n > qfs_left(qfs))
- n = qfs_left(qfs) ;
-
- if (n == 0)
- return ;
+ while (qfs->offset > 0)
+ {
+ if (*src++ == '\0')
+ return ;
+ --qfs->offset ;
+ } ;
- memcpy(qfs->ptr, src, n + 1) ;
- qfs->ptr += n ;
+ while (*src != '\0')
+ {
+ if (qfs->ptr < qfs->end)
+ *qfs->ptr++ = *src++ ;
+ else
+ ++qfs->overflow ;
+ } ;
} ;
/*------------------------------------------------------------------------------
@@ -147,43 +184,76 @@ qfs_append(qf_str qfs, const char* src)
*
* May append nothing at all !
*
- * This operation is async-signal-safe.
+ * src may be NULL iff n == 0
+ *
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
extern void
-qfs_append_n(qf_str qfs, const char* src, size_t n)
+qfs_append_n(qf_str qfs, const char* src, uint n)
{
- if ((int)n > qfs_left(qfs))
- n = qfs_left(qfs) ;
+ uint h ;
- if (n <= 0)
- return ;
+ if (qfs->offset > 0)
+ {
+ if (qfs->offset >= n)
+ {
+ qfs->offset -= n ;
+ return ;
+ } ;
- memcpy(qfs->ptr, src, n) ;
- qfs->ptr += n ;
+ src += qfs->offset ;
+ n -= qfs->offset ;
- *qfs->ptr = '\0' ;
+ qfs->offset = 0 ;
+ } ;
+
+ h = (qfs->end - qfs->ptr) ;
+ if (n > h)
+ {
+ qfs->overflow += n - h ;
+ n = h ;
+ } ;
+
+ while (n--)
+ *qfs->ptr++ = *src++ ;
} ;
/*------------------------------------------------------------------------------
- * Append upto 'n' copies of the given character to the qf_str
+ * Append upto 'n' copies of the given character to the qf_str.
*
* May append nothing at all !
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
extern void
-qfs_append_ch_x_n(qf_str qfs, char ch, size_t n)
+qfs_append_ch_x_n(qf_str qfs, char ch, uint n)
{
- if ((int)n > qfs_left(qfs))
- n = qfs_left(qfs) ;
+ uint h ;
- if (n <= 0)
- return ;
+ if (qfs->offset > 0)
+ {
+ if (qfs->offset >= n)
+ {
+ qfs->offset -= n ;
+ return ;
+ } ;
+
+ n -= qfs->offset ;
+
+ qfs->offset = 0 ;
+ } ;
+
+ h = (qfs->end - qfs->ptr) ;
+ if (n > h)
+ {
+ qfs->overflow += n - h ;
+ n = h ;
+ } ;
while (n--)
*qfs->ptr++ = ch ;
-
- *qfs->ptr = '\0' ;
} ;
/*------------------------------------------------------------------------------
@@ -196,19 +266,13 @@ qfs_append_ch_x_n(qf_str qfs, char ch, size_t n)
*
* May append nothing at all !
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
extern void
qfs_append_justified(qf_str qfs, const char* src, int width)
{
- size_t n ;
-
- if ((src == NULL) || (*src == '\0'))
- n = 0 ;
- else
- n = strlen(src) ;
-
- qfs_append_justified_n(qfs, src, n, width) ;
+ qfs_append_justified_n(qfs, src, qfs_strlen(src), width) ;
} ;
/*------------------------------------------------------------------------------
@@ -221,10 +285,11 @@ qfs_append_justified(qf_str qfs, const char* src, int width)
*
* May append nothing at all !
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
extern void
-qfs_append_justified_n(qf_str qfs, const char* src, size_t n, int width)
+qfs_append_justified_n(qf_str qfs, const char* src, uint n, int width)
{
if ((int)n >= abs(width))
width = 0 ;
@@ -238,6 +303,23 @@ qfs_append_justified_n(qf_str qfs, const char* src, size_t n, int width)
qfs_append_ch_x_n(qfs, ' ', - width - n) ;
} ;
+/*------------------------------------------------------------------------------
+ * Append single character.
+ *
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
+ */
+inline static void
+qfs_append_ch(qf_str qfs, char ch)
+{
+ if (qfs->offset > 0)
+ --qfs->offset ;
+ else if (qfs->ptr < qfs->end)
+ *qfs->ptr++ = ch ;
+ else
+ ++qfs->overflow ;
+} ;
+
/*==============================================================================
* Number conversion
*/
@@ -251,7 +333,8 @@ qfs_number(qf_str qfs, uintmax_t val, int sign, enum pf_flags flags,
*
* Result is appended to the given qf_str.
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
extern void
qfs_signed(qf_str qfs, intmax_t s_val, enum pf_flags flags,
@@ -279,7 +362,8 @@ qfs_signed(qf_str qfs, intmax_t s_val, enum pf_flags flags,
*
* Result is appended to the given qf_str.
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
extern void
qfs_unsigned(qf_str qfs, uintmax_t u_val, enum pf_flags flags,
@@ -293,7 +377,8 @@ qfs_unsigned(qf_str qfs, uintmax_t u_val, enum pf_flags flags,
*
* Result is appended to the given qf_str.
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
extern void
qfs_pointer(qf_str qfs, void* p_val, enum pf_flags flags,
@@ -358,7 +443,8 @@ qfs_pointer(qf_str qfs, void* p_val, enum pf_flags flags,
* characters are to be generated -- ie no: pf_plus, pf_space, pf_zeros,
* or pf_alt (with pf_hex) -- then nothing is generated.
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
static void
qfs_number(qf_str qfs, uintmax_t val, int sign, enum pf_flags flags,
@@ -473,8 +559,7 @@ qfs_number(qf_str qfs, uintmax_t val, int sign, enum pf_flags flags,
base = (flags & pf_hex) ? 16 : 10 ;
digits = (flags & pf_uc) ? uc : lc ;
- e = p = num + sizeof(num) - 1 ;
- *p = '\0' ;
+ e = p = num + sizeof(num) ;
v = val ;
do
{
@@ -646,7 +731,7 @@ enum arg_num_type
ant_long_long, /* ll */
ant_intmax_t, /* j */
ant_size_t, /* z */
- ant_ptr_t, /* void* */
+ ant_ptr_t, /* %p */
ant_default = ant_int,
};
@@ -659,42 +744,51 @@ static enum pf_phase qfs_arg_number(qf_str qfs, va_list* p_va,
enum pf_flags flags, int width, int precision, enum arg_num_type ant) ;
/*------------------------------------------------------------------------------
- * Formatted print to qf_str -- cf printf()
+ * Formatted print to qf_str -- cf printf() -- appends to the qf_str.
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow.
+ *
+ * Returns: the resulting length of the qf_str.
*/
-extern void
+extern uint
qfs_printf(qf_str qfs, const char* format, ...)
{
va_list va ;
+ uint did ;
va_start (va, format);
- qfs_vprintf(qfs, format, va);
+ did = qfs_vprintf(qfs, format, va);
va_end (va);
+
+ return did ;
} ;
/*------------------------------------------------------------------------------
- * Formatted print to qf_str -- cf vprintf()
+ * Formatted print to qf_str -- cf vprintf() -- appends to the qf_str.
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*
* Operates on a copy of the va_list -- so the original is *unchanged*.
+ *
+ * Returns: the resulting length of the qf_str.
*/
-extern void
+extern uint
qfs_vprintf(qf_str qfs, const char *format, va_list va)
{
va_list vac ;
if (format == NULL)
- return ;
+ return qfs_len(qfs) ;
va_copy(vac, va) ;
- while ((qfs->ptr < qfs->end) && (*format != '\0'))
+ while (*format != '\0')
{
/* Have space for one byte and current format byte is not '\0' */
if (*format != '%')
- *qfs->ptr++ = *format++ ;
+ qfs_append_ch(qfs, *format++) ;
else
{
const char* start = format++ ; /* start points at the '%' ...
@@ -715,8 +809,12 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
{
case '%': /* %% only */
if (phase == pfp_null)
- *qfs->ptr++ = '%' ;
- phase = (phase == pfp_null) ? pfp_done : pfp_failed ;
+ {
+ qfs_append_ch(qfs, '%') ;
+ phase = pfp_done ;
+ }
+ else
+ phase = pfp_failed ;
break ;
case '\'':
@@ -881,14 +979,14 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
if (phase == pfp_failed)
{
format = start ; /* back to the start */
- *qfs->ptr++ = *format++ ; /* copy the '%' */
+ qfs_append_ch(qfs, *format++) ;
} ;
} ;
} ;
- *qfs->ptr = '\0' ;
-
va_end(vac) ;
+
+ return qfs_len(qfs) ;
} ;
/*------------------------------------------------------------------------------
@@ -909,7 +1007,8 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
* pf_unsigned
* pf_ptr
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
static enum pf_phase
qfs_arg_string(qf_str qfs, const char* src, enum pf_flags flags,
@@ -953,7 +1052,8 @@ qfs_arg_string(qf_str qfs, const char* src, enum pf_flags flags,
* pf_unsigned
* pf_ptr
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
static enum pf_phase
qfs_arg_char(qf_str qfs, char ch, enum pf_flags flags, int width, int precision)
@@ -985,7 +1085,8 @@ qfs_arg_char(qf_str qfs, char ch, enum pf_flags flags, int width, int precision)
*
* and: all the number argument types.
*
- * This operation is async-signal-safe.
+ * This operation is async-signal-safe. Takes into account the offset, and
+ * adds up any overflow
*/
static enum pf_phase
qfs_arg_number(qf_str qfs, va_list* p_va, enum pf_flags flags,
diff --git a/lib/qfstring.h b/lib/qfstring.h
index c57bd4ea..f6eb1807 100644
--- a/lib/qfstring.h
+++ b/lib/qfstring.h
@@ -28,20 +28,31 @@
/*==============================================================================
* These "qfstrings" address the issues of dealing with *fixed* length
* strings, particularly where the string handling must be async-signal-safe.
+ *
+ * Are also used to support snprintf() style printing, but to one or more
+ * fixed length buffers.
*/
/* When initialised a qf_string is set:
*
- * str = start of string -- and this is never changed
- * ptr = start of string -- this is moved as stuff is appended
- * end = last possible position for terminating '\0'
- * -- and this is never changed
+ * str = start of string -- and this is never changed
+ * ptr = start of string -- this is moved as stuff is appended
+ * end = end of string -- and this is never changed
+ * offset = number of characters left to omit -- used to collect a long
+ * string in more than one section
+ * overflow = number of characters that had to leave out, because string
+ * was too short.
+ *
+ * When filling the string, will work right up to the byte just before the
+ * end. Does not terminate the string -- that must be done explicitly.
*/
struct qf_str
{
- char* str ; /* start of string */
- char* ptr ; /* current position */
- char* end ; /* end of string */
+ char* str ; /* start of string */
+ char* ptr ; /* current position */
+ char* end ; /* end of string */
+ uint offset ; /* number of chars to omit */
+ uint overflow ; /* number of excess chars */
} ;
typedef struct qf_str qf_str_t[1] ;
@@ -82,22 +93,26 @@ enum pf_flags
* Functions
*/
-extern void qfs_init(qf_str qfs, char* str, size_t size) ;
-extern void qfs_init_as_is(qf_str qfs, char* str, size_t size) ;
+extern void qfs_init(qf_str qfs, char* str, uint size) ;
+extern void qfs_init_offset(qf_str qfs, char* str, uint size, uint offset) ;
+extern void qfs_reset_offset(qf_str qfs, uint offset) ;
+extern void qfs_init_as_is(qf_str qfs, char* str, uint size) ;
-extern void qfs_term(qf_str qfs, const char* src) ;
+Inline uint qfs_overflow(qf_str qfs) ;
+Inline uint qfs_term(qf_str qfs) ;
+extern void qfs_term_string(qf_str qfs, const char* src, uint n) ;
-Inline int qfs_len(qf_str qfs) ;
+Inline uint qfs_len(qf_str qfs) ;
Inline void* qfs_ptr(qf_str qfs) ;
-Inline int qfs_left(qf_str qfs) ;
+Inline uint qfs_left(qf_str qfs) ;
extern void qfs_append(qf_str qfs, const char* src) ;
-extern void qfs_append_n(qf_str qfs, const char* src, size_t n) ;
+extern void qfs_append_n(qf_str qfs, const char* src, uint n) ;
-extern void qfs_append_ch_x_n(qf_str qfs, char ch, size_t n) ;
+extern void qfs_append_ch_x_n(qf_str qfs, char ch, uint n) ;
extern void qfs_append_justified(qf_str qfs, const char* src, int width) ;
extern void qfs_append_justified_n(qf_str qfs, const char* src,
- size_t n, int width) ;
+ uint n, int width) ;
extern void qfs_signed(qf_str qfs, intmax_t s_val, enum pf_flags flags,
int width, int precision) ;
@@ -106,25 +121,27 @@ extern void qfs_unsigned(qf_str qfs, uintmax_t u_val, enum pf_flags flags,
extern void qfs_pointer(qf_str qfs, void* p_val, enum pf_flags flags,
int width, int precision) ;
-extern void qfs_printf(qf_str qfs, const char* format, ...)
+extern uint qfs_printf(qf_str qfs, const char* format, ...)
PRINTF_ATTRIBUTE(2, 3) ;
-extern void qfs_vprintf(qf_str qfs, const char *format, va_list args) ;
+extern uint qfs_vprintf(qf_str qfs, const char *format, va_list args) ;
+
+Inline uint qfs_strlen(const char* str) ;
/*==============================================================================
* The Inline functions.
*/
/*------------------------------------------------------------------------------
- * Current length of qf_str, not counting the terminating '\0'.
+ * Current length of qf_str.
*/
-Inline int
+Inline uint
qfs_len(qf_str qfs)
{
return qfs->ptr - qfs->str ;
} ;
/*------------------------------------------------------------------------------
- * Address of the terminating '\0'.
+ * Address for next byte -- assuming zero offset -- may be the end.
*/
Inline void*
qfs_ptr(qf_str qfs)
@@ -133,14 +150,63 @@ qfs_ptr(qf_str qfs)
} ;
/*------------------------------------------------------------------------------
- * Current space left in the qstr, given what has been reserved for terminating
- * '\0' and any other reservation.
+ * Current space left in the qstr -- assuming zero offset.
*/
-Inline int
+Inline uint
qfs_left(qf_str qfs)
{
return qfs->end - qfs->ptr ;
} ;
+/*------------------------------------------------------------------------------
+ * Did everything we put in the qfs, fit ?.
+ *
+ * Returns: number of chars that did *not* fit.
+ */
+Inline uint
+qfs_overflow(qf_str qfs)
+{
+ return qfs->overflow ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Insert '\0' terminator -- overwrites the last byte, if required.
+ *
+ * Assumes the qfs is not zero length !
+ *
+ * Returns: number of chars that did *not* fit (after using one for '\0').
+ *
+ * NB: does not advance pointer -- so length does not include the '\0'
+ */
+Inline uint
+qfs_term(qf_str qfs)
+{
+ if (qfs->ptr >= qfs->end)
+ {
+ assert((qfs->ptr == qfs->end) && (qfs->ptr > qfs->str)) ;
+ --qfs->ptr ;
+ ++qfs->overflow ;
+ } ;
+
+ *qfs->ptr = '\0' ;
+ return qfs->overflow ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * async-signal-safe strlen
+ */
+Inline uint
+qfs_strlen(const char* str)
+{
+ const char* s ;
+
+ s = str ;
+
+ if (s != NULL)
+ while (*s != '\0')
+ ++s ;
+
+ return s - str ;
+}
#endif /* _ZEBRA_QSTRING_H */
diff --git a/lib/qiovec.c b/lib/qiovec.c
index 2946efaa..cc24503e 100644
--- a/lib/qiovec.c
+++ b/lib/qiovec.c
@@ -18,10 +18,9 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
-#include "zconfig.h" /* Otherwise IOV_MAX is not defined ! */
+#include "misc.h"
#include <errno.h>
-#include "misc.h"
#include "qdebug_nb.h"
#include "memory.h"
diff --git a/lib/qlib_init.c b/lib/qlib_init.c
index d3fde339..757a9e65 100644
--- a/lib/qlib_init.c
+++ b/lib/qlib_init.c
@@ -18,7 +18,7 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
-
+#include "misc.h"
#include "qlib_init.h"
#include "zassert.h"
#include "memory.h"
diff --git a/lib/qpath.c b/lib/qpath.c
index e3f690a6..28757f11 100644
--- a/lib/qpath.c
+++ b/lib/qpath.c
@@ -18,7 +18,7 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
-
+#include "misc.h"
#include "qpath.h"
#include "qstring.h"
diff --git a/lib/qpthreads.h b/lib/qpthreads.h
index 926d11e5..d05f7e34 100644
--- a/lib/qpthreads.h
+++ b/lib/qpthreads.h
@@ -22,8 +22,6 @@
#ifndef _ZEBRA_QPTHREADS_H
#define _ZEBRA_QPTHREADS_H
-#include "zconfig.h"
-
#include "misc.h"
#include <time.h>
#include <pthread.h>
diff --git a/lib/qrand.c b/lib/qrand.c
index ff52afd4..402bb432 100644
--- a/lib/qrand.c
+++ b/lib/qrand.c
@@ -18,7 +18,7 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
-
+#include "misc.h"
#include "qrand.h"
/*==============================================================================
diff --git a/lib/qstring.c b/lib/qstring.c
index d00e3b70..97f8e8b0 100644
--- a/lib/qstring.c
+++ b/lib/qstring.c
@@ -18,7 +18,7 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
-
+#include "misc.h"
#include "stdio.h"
#include "qstring.h"
diff --git a/lib/qtime.c b/lib/qtime.c
index 44a27b0f..789ced1e 100644
--- a/lib/qtime.c
+++ b/lib/qtime.c
@@ -18,11 +18,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+#include "misc.h"
#include <sys/times.h>
#include <errno.h>
-#include "zassert.h"
#include "qtime.h"
/*==============================================================================
@@ -69,6 +69,7 @@
* (It appears that 60, 100, 250 and 1,000 ticks/sec. are popular options.)
*
* If sizeof(clock_t) > 4, it is assumed large enough never to wrap around.
+ * (But seems unlikely that such a system would not support CLOCK_MONOTONIC !)
*
* When clock_t is a 32-bit integer must be at least ready for wrap around.
* There are two cases:
@@ -97,23 +98,24 @@ CONFIRM((sizeof(clock_t) >= 4) && (sizeof(clock_t) <= 8)) ;
#ifdef GNU_LINUX
#define TIMES_TAKES_NULL 1
#else
-#undef TIMES_TAKES_NULL
+#define TIMES_TAKES_NULL 0
#endif
-static uint64_t monotonic = 0 ; /* monotonic clock in _SC_CLK_TCK's */
-static int64_t last_times_sample = 0 ; /* last value returned by times() */
+static int64_t monotonic = 0 ; /* monotonic clock in _SC_CLK_TCK's */
+static int64_t last_times_sample = 0 ; /* last value returned by times() */
-static uint64_t step_limit = 0 ; /* for sanity check */
+static int64_t step_limit = 0 ; /* for sanity check */
-static int64_t times_clk_tcks = 0 ; /* sysconf(_SC_CLK_TCK) */
-static qtime_t times_scale_q = 0 ; /* 10**9 / times_clk_tcks */
-static qtime_t times_scale_r = 0 ; /* 10**9 % times_clk_tcks */
+static int64_t times_clk_tcks = 0 ; /* sysconf(_SC_CLK_TCK) */
+static qtime_t times_scale_q = 0 ; /* 10**9 / times_clk_tcks */
+static qtime_t times_scale_r = 0 ; /* 10**9 % times_clk_tcks */
qtime_mono_t
qt_craft_monotonic(void) {
- struct tms dummy ;
- int64_t this_times_sample ;
- uint64_t step ;
+#if !TIMES_TAKES_NULL
+ struct tms dummy[1] ;
+#endif
+ clock_t this_times_sample ;
/* Set up times_scale_q & times_scale_q if not yet done. */
if (times_clk_tcks == 0) /* Is zero until it's initialized */
@@ -130,7 +132,7 @@ qt_craft_monotonic(void) {
times_scale_q = qr.quot ;
times_scale_r = qr.rem ;
- step_limit = (uint64_t)24 * 60 * 60 * times_clk_tcks ;
+ step_limit = (int64_t)24 * 60 * 60 * times_clk_tcks ;
} ;
/* No errors are defined for times(), but a return of -1 is defined */
@@ -139,52 +141,55 @@ qt_craft_monotonic(void) {
/* The following deals carefully with this -- cannot afford for the */
/* clock either to jump or to get stuck ! */
-#ifdef TIMES_TAKES_NULL
- this_times_sample = times(NULL) ; /* assume this saves effort ! */
+#if TIMES_TAKES_NULL
+# define TIMES_ARG NULL
#else
- this_times_sample = times(&dummy) ;
+# define TIMES_ARG dummy
#endif
+ this_times_sample = times(TIMES_ARG) ;
if (this_times_sample == -1) /* deal with theoretical error */
{
errno = 0 ;
- this_times_sample = times(&dummy) ;
+ this_times_sample = times(TIMES_ARG) ;
if (errno != 0)
zabort_errno("times() failed") ;
} ;
+#undef TIMES_ARG
- /* Calculate the step and verify sensible. */
- /* */
- /* Watch out for huge jumps and/or time going backwards. */
- /* For 32-bit clock_t, look out for wrap-around. */
-
- if ((sizeof(clock_t) > 4) || (this_times_sample > last_times_sample))
- /* time going backwards will appear as HUGE step forwards. */
- step = (uint64_t)(this_times_sample - last_times_sample) ;
+ /* If clock_t is large enough, treat as monotonic (!).
+ *
+ * Otherwise calculate the difference between this sample and the
+ * previous one -- the step.
+ *
+ * We do the sum in signed 64 bits, and the samples are signed 64 bits.
+ */
+ if (sizeof(clock_t) > 4)
+ monotonic = this_times_sample ;
else
{
- if (this_times_sample > 0)
- /* both samples +ve => +ve wrap around. */
- step = (uint64_t)( ((int64_t)INT32_MAX - last_times_sample + 1)
- + this_times_sample ) ;
- else
- /* this sample -ve and last sample +ve => -ve wrap round */
- /* this sample -ve and last sample -ve => time gone backwards */
- /* (which appears as a HUGE step forwards). */
- step = (uint64_t)( ((int64_t)INT32_MAX - last_times_sample + 1)
- - ((int64_t)INT32_MIN - this_times_sample) ) ;
+ int64_t step ;
+
+ step = this_times_sample - last_times_sample ;
+
+ while (step < 0)
+ {
+ /* If times() wraps unsigned, then result needs INT32_MAX + 1
+ * adding to it to get to +ve result.
+ *
+ * If times() wraps signed, then result needs INT32_MAX + 1 adding
+ * to it *twice*.
+ */
+ step += (uint64_t)INT32_MAX + 1 ;
+ } ;
+
+ if (step > step_limit)
+ zabort("Sudden large monotonic clock jump") ;
+
+ monotonic += step ;
+ last_times_sample = this_times_sample ;
} ;
- /* TODO: better error messaging for large clock jumps. */
- if (step > step_limit)
- zabort("Sudden large monotonic clock jump") ;
-
- /* Advance the monotonic clock in sysconf(_SC_CLK_TCK) units. */
- monotonic += step ;
-
- /* Remember what we got, for next time. */
- last_times_sample = this_times_sample ;
-
/* Scale to qtime_t units. */
if (times_scale_r == 0)
return monotonic * times_scale_q ;
@@ -193,6 +198,17 @@ qt_craft_monotonic(void) {
((monotonic * times_scale_r) / times_clk_tcks) ;
} ;
+/*------------------------------------------------------------------------------
+ * Get crafted monotonic time -- in seconds
+ */
+extern time_t
+qt_craft_mono_secs(void)
+{
+ qt_craft_monotonic() ; /* update the monotonic counter */
+
+ return monotonic / times_clk_tcks ;
+} ;
+
/*==============================================================================
* A simple minded random number generator.
*
diff --git a/lib/qtime.h b/lib/qtime.h
index 38d717c0..577c34a3 100644
--- a/lib/qtime.h
+++ b/lib/qtime.h
@@ -96,6 +96,9 @@ Inline qtime_mono_t qt_get_monotonic(void) ;
/* OR equivalent using times() */
Inline qtime_mono_t qt_add_monotonic(qtime_t interval) ;
/* qt_get_monotonic() + interval */
+Inline time_t qt_get_mono_secs(void) ;
+ /* clock_gettime(CLOCK_MONOTONIC, ...) */
+ /* OR equivalent using times() */
/* These are provided just in case gettimeofday() != CLOCK_REALTIME */
Inline qtime_tod_t qt_get_timeofday(void) ;
@@ -181,6 +184,7 @@ qtime2timeval(struct timeval* p_tv, qtime_t qt)
/* Function to manufacture a monotonic clock. */
Private qtime_mono_t qt_craft_monotonic(void) ;
+Private time_t qt_craft_mono_secs(void) ;
/*------------------------------------------------------------------------------
* Read given clock & return a qtime_t value.
@@ -248,6 +252,30 @@ qt_add_monotonic(qtime_t interval)
} ;
/*------------------------------------------------------------------------------
+ * clock_gettime(CLOCK_MONOTONIC, ...) OR qt_craft_monotonic()
+ * -- returning time_t value
+ *
+ * Value returned is in seconds -- for coarser grain timings.
+ *
+ * While possibility of error is essentially theoretical, must treat it as a
+ * FATAL error -- cannot continue with broken time value !
+ */
+Inline time_t
+qt_get_mono_secs(void)
+{
+#ifdef HAVE_CLOCK_MONOTONIC
+ struct timespec ts ;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+ zabort_errno("clock_gettime failed") ;
+
+ return ts.tv_sec ;
+#else
+ return qt_craft_mono_secs() ;
+#endif
+} ;
+
+/*------------------------------------------------------------------------------
* gettimeofday(&tv, NULL) -- returning qtime_t value
*/
Inline qtime_tod_t
diff --git a/lib/qtimers.c b/lib/qtimers.c
index 6ccb7f7d..3af79d7b 100644
--- a/lib/qtimers.c
+++ b/lib/qtimers.c
@@ -18,11 +18,8 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+#include "misc.h"
-#include <stddef.h>
-#include <string.h>
-
-#include "zassert.h"
#include "qtimers.h"
#include "memory.h"
#include "heap.h"
diff --git a/lib/regex.c b/lib/regex.c
index a22e03f6..425f3c8e 100644
--- a/lib/regex.c
+++ b/lib/regex.c
@@ -27,9 +27,8 @@
#undef _GNU_SOURCE
#define _GNU_SOURCE
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include "misc.h"
+
#ifdef _WIN32
/* Windows does not provide unistd.h, which is required for abort() */
#include <process.h>
@@ -209,7 +208,7 @@ init_syntax_once ()
# define SYNTAX(c) re_syntax_table[c]
#endif /* not emacs */
-
+
/* Get the interface, including the syntax bits. */
#include <regex-gnu.h>
@@ -279,7 +278,7 @@ init_syntax_once ()
/* As in Harbison and Steele. */
# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
#endif
-
+
/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
use `alloca' instead of `malloc'. This is because using malloc in
re_search* or re_match* could cause memory leaks when C-g is used in
@@ -388,7 +387,7 @@ static int re_match_2_internal PARAMS ((struct re_pattern_buffer *bufp,
int pos,
struct re_registers *regs,
int stop));
-
+
/* These are the command codes that appear in compiled regular
expressions. Some opcodes are followed by argument bytes. A
command code can specify any interpretation whatsoever for its
@@ -527,7 +526,7 @@ typedef enum
notsyntaxspec
#endif /* emacs */
} re_opcode_t;
-
+
/* Common operations on the compiled pattern. */
/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
@@ -604,7 +603,7 @@ extract_number_and_incr (destination, source)
# endif /* not EXTRACT_MACROS */
#endif /* DEBUG */
-
+
/* If DEBUG is defined, Regex prints many voluminous messages about what
it is doing (if the variable `debug' is nonzero). If linked with the
main program in `iregex.c', you can enter patterns and strings
@@ -977,7 +976,7 @@ printchar (c)
# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
#endif /* not DEBUG */
-
+
/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
also be assigned to arbitrarily: each pattern buffer stores its own
syntax, so it can be changed between regex compilations. */
@@ -1011,7 +1010,7 @@ re_set_syntax (syntax)
#ifdef _LIBC
weak_alias (__re_set_syntax, re_set_syntax)
#endif
-
+
/* This table gives an error message for each of the error codes listed
in regex.h. Obviously the order here has to be same as there.
POSIX doesn't require that we do anything for REG_NOERROR,
@@ -1091,7 +1090,7 @@ static const size_t re_error_msgid_idx[] =
REG_ESIZE_IDX,
REG_ERPAREN_IDX
};
-
+
/* Avoiding alloca during matching, to placate r_alloc. */
/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
@@ -1129,7 +1128,7 @@ static const size_t re_error_msgid_idx[] =
# undef MATCH_MAY_ALLOCATE
#endif
-
+
/* Failure stack declarations and macros; both re_compile_fastmap and
re_match_2 use a failure stack. These have to be macros because of
REGEX_ALLOCATE_STACK. */
@@ -1495,7 +1494,7 @@ typedef struct
} /* POP_FAILURE_POINT */
-
+
/* Structure for per-register (a.k.a. per-group) information.
Other register information, such as the
starting and ending positions (which are addresses), and the list of
@@ -1555,7 +1554,7 @@ typedef union
static char reg_unset_dummy;
#define REG_UNSET_VALUE (&reg_unset_dummy)
#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
-
+
/* Subroutine declarations and macros for regex_compile. */
static reg_errcode_t regex_compile _RE_ARGS ((const char *pattern, size_t size,
@@ -1809,7 +1808,7 @@ typedef struct
|| STREQ (string, "punct") || STREQ (string, "graph") \
|| STREQ (string, "cntrl") || STREQ (string, "blank"))
#endif
-
+
#ifndef MATCH_MAY_ALLOCATE
/* If we cannot allocate large objects within re_match_2_internal,
@@ -1857,7 +1856,7 @@ regex_grow_registers (num_regs)
}
#endif /* not MATCH_MAY_ALLOCATE */
-
+
static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type
compile_stack,
regnum_t regnum));
@@ -2991,7 +2990,7 @@ regex_compile (pattern, size, syntax, bufp)
return REG_NOERROR;
} /* regex_compile */
-
+
/* Subroutines for `regex_compile'. */
/* Store OP at LOC followed by two-byte integer parameter ARG. */
@@ -3178,7 +3177,7 @@ compile_range (p_ptr, pend, translate, syntax, b)
return REG_NOERROR;
}
-
+
/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
characters can start a string that matches the pattern. This fastmap
@@ -3484,7 +3483,7 @@ re_compile_fastmap (bufp)
#ifdef _LIBC
weak_alias (__re_compile_fastmap, re_compile_fastmap)
#endif
-
+
/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
this memory for recording register information. STARTS and ENDS
@@ -3522,7 +3521,7 @@ re_set_registers (bufp, regs, num_regs, starts, ends)
#ifdef _LIBC
weak_alias (__re_set_registers, re_set_registers)
#endif
-
+
/* Searching routines. */
/* Like re_search_2, below, but only one string is specified, and
@@ -3704,7 +3703,7 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
#ifdef _LIBC
weak_alias (__re_search_2, re_search_2)
#endif
-
+
/* This converts PTR, a pointer into one of the search strings `string1'
and `string2' into an offset from the beginning of that string. */
#define POINTER_TO_OFFSET(ptr) \
@@ -3783,7 +3782,7 @@ weak_alias (__re_search_2, re_search_2)
to actually save any registers when none are active. */
#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
-
+
/* Matching routines. */
#ifndef emacs /* Emacs never uses this. */
@@ -5248,7 +5247,7 @@ re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
return -1; /* Failure to match. */
} /* re_match_2 */
-
+
/* Subroutine definitions for re_match_2. */
@@ -5511,7 +5510,7 @@ bcmp_translate (s1, s2, len, translate)
}
return 0;
}
-
+
/* Entry points for GNU code. */
/* re_compile_pattern is the GNU regular expression compiler: it
@@ -5552,7 +5551,7 @@ re_compile_pattern (pattern, length, bufp)
#ifdef _LIBC
weak_alias (__re_compile_pattern, re_compile_pattern)
#endif
-
+
/* Entry points compatible with 4.2 BSD regex library. We don't define
them unless specifically requested. */
@@ -5623,7 +5622,7 @@ re_exec (s)
}
#endif /* _REGEX_RE_COMP */
-
+
/* POSIX.2 functions. Don't define these for Emacs. */
#ifndef emacs
diff --git a/lib/sockopt.c b/lib/sockopt.c
index a8fae4f1..aa747429 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -641,8 +641,13 @@ sockopt_tcp_signature (int sock_fd, union sockunion *su, const char *password)
su2->sin6.sin6_family = AF_INET6;
/* V4Map the address */
memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
- su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
- memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4);
+ su2->sin6.sin6_addr.s6_addr[10] = 0xff ;
+ su2->sin6.sin6_addr.s6_addr[11] = 0xff ;
+# ifdef s6_addr32
+ su2->sin6.sin6_addr.s6_addr32[3] = su->sin.sin_addr.s_addr ;
+# else
+ memcpy (&su2->sin6.sin6_addr.s6_addr[12], &su->sin.sin_addr, 4);
+# endif
}
# endif
}
diff --git a/lib/sockunion.c b/lib/sockunion.c
index e08a3745..deac292c 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -20,6 +20,7 @@
*/
#include <zebra.h>
+#include "misc.h"
#include "prefix.h"
#include "vty.h"
diff --git a/lib/stream.c b/lib/stream.c
index 1fce7103..0183ce78 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -20,8 +20,8 @@
* 02111-1307, USA.
*/
+#include "zebra.h"
#include <stddef.h>
-#include <zebra.h>
#include "stream.h"
#include "memory.h"
diff --git a/lib/table.c b/lib/table.c
index 04df3af5..e40e6707 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -209,6 +209,10 @@ route_node_match (const struct route_table *table, const struct prefix *p)
{
if (node->info)
matched = node;
+
+ if (node->p.prefixlen == p->prefixlen)
+ break;
+
node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
}
@@ -260,8 +264,8 @@ route_node_lookup (struct route_table *table, struct prefix *p)
while (node && node->p.prefixlen <= p->prefixlen &&
prefix_match (&node->p, p))
{
- if (node->p.prefixlen == p->prefixlen && node->info)
- return route_lock_node (node);
+ if (node->p.prefixlen == p->prefixlen)
+ return node->info ? route_lock_node (node) : NULL;
node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
}
@@ -283,10 +287,8 @@ route_node_get (struct route_table *table, struct prefix *p)
prefix_match (&node->p, p))
{
if (node->p.prefixlen == p->prefixlen)
- {
- route_lock_node (node);
- return node;
- }
+ return route_lock_node (node);
+
match = node;
node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
}
diff --git a/lib/thread.c b/lib/thread.c
index cf2ec425..90aad4ba 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -228,6 +228,9 @@ recent_relative_time (void)
return relative_time;
}
+/* Uses the address of the function (or at least ls part of same) as the hash
+ * key. (The function name is for display, only.)
+ */
static unsigned int
cpu_record_hash_key (struct cpu_thread_history *a)
{
@@ -288,15 +291,14 @@ static void
cpu_record_hash_free (void *a)
{
struct cpu_thread_history *hist = a;
- void* funcname = miyagi(hist->funcname) ;
- XFREE (MTYPE_THREAD_FUNCNAME, funcname);
+ XFREE (MTYPE_THREAD_FUNCNAME, hist->funcname);
XFREE (MTYPE_THREAD_STATS, hist);
}
static inline void
vty_out_cpu_thread_history(struct vty* vty,
- struct cpu_thread_history *a)
+ const struct cpu_thread_history *a)
{
#ifdef HAVE_RUSAGE
vty_out(vty, "%7ld.%03ld %9d %8ld %9ld %8ld %9ld",
@@ -349,7 +351,9 @@ cpu_record_print(struct vty *vty, thread_type filter)
void *args[3] = {&tmp, vty, &filter};
memset(&tmp, 0, sizeof tmp);
- tmp.funcname = "TOTAL";
+ tmp.funcname = miyagi("TOTAL"); /* NB: will not free tmp in the usual way,
+ in particular, will not attempt
+ to free this !! */
tmp.types = filter;
#ifdef HAVE_RUSAGE
@@ -433,6 +437,89 @@ DEFUN_CALL(show_thread_cpu,
return CMD_SUCCESS;
}
+static void
+cpu_record_hash_clear (struct hash_backet *bucket,
+ void *args)
+{
+ thread_type *filter = args;
+ struct cpu_thread_history *a = bucket->data;
+
+ a = bucket->data;
+ if ( !(a->types & *filter) )
+ return;
+
+ hash_release (cpu_record, bucket->data);
+}
+
+static void
+cpu_record_clear (thread_type filter)
+{
+ thread_type *tmp = &filter;
+ hash_iterate (cpu_record,
+ (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
+ tmp);
+}
+
+DEFUN(clear_thread_cpu,
+ clear_thread_cpu_cmd,
+ "clear thread cpu [FILTER]",
+ "Clear stored data\n"
+ "Thread information\n"
+ "Thread CPU usage\n"
+ "Display filter (rwtexb)\n")
+{
+ int i = 0;
+ thread_type filter = (thread_type) -1U;
+
+ if (argc > 0)
+ {
+ filter = 0;
+ while (argv[0][i] != '\0')
+ {
+ switch ( argv[0][i] )
+ {
+ case 'r':
+ case 'R':
+ filter |= (1 << THREAD_READ);
+ break;
+ case 'w':
+ case 'W':
+ filter |= (1 << THREAD_WRITE);
+ break;
+ case 't':
+ case 'T':
+ filter |= (1 << THREAD_TIMER);
+ break;
+ case 'e':
+ case 'E':
+ filter |= (1 << THREAD_EVENT);
+ break;
+ case 'x':
+ case 'X':
+ filter |= (1 << THREAD_EXECUTE);
+ break;
+ case 'b':
+ case 'B':
+ filter |= (1 << THREAD_BACKGROUND);
+ break;
+ default:
+ break;
+ }
+ ++i;
+ }
+ if (filter == 0)
+ {
+ vty_out(vty, "Invalid filter \"%s\" specified,"
+ " must contain at least one of 'RWTEXB'%s",
+ argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ cpu_record_clear (filter);
+ return CMD_SUCCESS;
+}
+
/* List allocation and head/tail print out. */
static void
thread_list_debug (struct thread_list *list)
@@ -630,9 +717,16 @@ thread_get_hist(struct thread* thread, const char* funcname)
struct cpu_thread_history* hist ;
tmp.func = thread->func ;
- tmp.funcname = funcname ;
-
+ tmp.funcname = miyagi(funcname); /* NB: will not free tmp in the usual way,
+ in particular, will not attempt
+ to free this !! */
LOCK
+
+ /* This looks up entry which matches the tmp just set up.
+ *
+ * If does not find one, allocates a new one -- taking a copy of the
+ * funcname.
+ */
hist = hash_get (cpu_record, &tmp,
(void * (*) (void *))cpu_record_hash_alloc);
UNLOCK
@@ -1121,6 +1215,26 @@ thread_timer_process (struct thread_list *list, struct timeval *timenow)
}
/*------------------------------------------------------------------------------
+ * Move the given list of threads to the back of the THREAD_READY queue.
+ */
+/* process a list en masse, e.g. for event thread lists */
+static unsigned int
+thread_process (struct thread_list *list)
+{
+ struct thread *thread;
+ unsigned int ready = 0;
+
+ for (thread = list->head; thread; thread = thread->next)
+ {
+ thread_list_delete (list, thread);
+ thread->type = THREAD_READY;
+ thread_list_add (&thread->master->ready, thread);
+ ready++;
+ }
+ return ready;
+}
+
+/*------------------------------------------------------------------------------
* Fetch next ready thread -- for standard thread handing.
*
* (This is not used when using qtimer_pile, or qnexus stuff.)
@@ -1141,25 +1255,31 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
{
int num = 0;
- /* Signals are highest priority */
+ /* Signals pre-empt everything */
quagga_sigevent_process ();
- /* Normal event are the next highest priority. */
- if ((thread = thread_trim_head (&m->event)) != NULL)
- return thread_run (m, thread, fetch);
-
- /* If there are any ready threads from previous scheduler runs,
- * process top of them.
+ /* Drain the ready queue of already scheduled jobs, before scheduling
+ * more.
*/
if ((thread = thread_trim_head (&m->ready)) != NULL)
return thread_run (m, thread, fetch);
+ /* To be fair to all kinds of threads, and avoid starvation, we
+ * need to be careful to consider all thread types for scheduling
+ * in each quanta. I.e. we should not return early from here on.
+ */
+
+ /* Normal event are the next highest priority. */
+ thread_process (&m->event);
+
/* Structure copy. */
readfd = m->readfd;
writefd = m->writefd;
exceptfd = m->exceptfd;
/* Calculate select wait timer if nothing else to do */
+ if (m->ready.count == 0)
+ {
quagga_get_relative (NULL);
timer_wait = thread_timer_wait (&m->timer, &timer_val);
timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
@@ -1167,6 +1287,13 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
if (timer_wait_bg &&
(!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
timer_wait = timer_wait_bg;
+ }
+ else
+ {
+ timer_val.tv_sec = 0 ;
+ timer_val.tv_usec = 0 ;
+ timer_wait = &timer_val ;
+ } ;
num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
diff --git a/lib/thread.h b/lib/thread.h
index 6f74876d..d9c58640 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -87,7 +87,7 @@ struct thread
struct cpu_thread_history
{
int (*func)(struct thread *);
- const char *funcname;
+ char *funcname;
unsigned int total_calls;
struct time_stats
{
@@ -207,6 +207,7 @@ extern int thread_should_yield (struct thread *);
/* Internal libzebra exports */
extern void thread_getrusage (RUSAGE_T *);
extern struct cmd_command show_thread_cpu_cmd;
+extern struct cmd_command clear_thread_cpu_cmd;
/* replacements for the system gettimeofday(), clock_gettime() and
* time() functions, providing support for non-decrementing clock on
diff --git a/lib/vector.c b/lib/vector.c
index 15371930..cd81191f 100644
--- a/lib/vector.c
+++ b/lib/vector.c
@@ -22,7 +22,7 @@
* 02111-1307, USA.
*/
-//#include <zebra.h>
+#include "misc.h"
#include "vector.h"
#include "memory.h"
diff --git a/lib/vio_fifo.c b/lib/vio_fifo.c
index 46a087f7..52e0d2df 100644
--- a/lib/vio_fifo.c
+++ b/lib/vio_fifo.c
@@ -21,9 +21,9 @@
#include "misc.h"
#include <stdio.h>
-#include <string.h>
#include "vio_fifo.h"
+#include "qfstring.h"
#include "network.h"
#include "memory.h"
@@ -42,17 +42,17 @@
*------------------------------------------------------------------------------
* Implementation notes:
*
- * The FIFO is initialised with all pointers NULL -- so with no lumps at all.
+ * The FIFO is initialised with one lump in it (the "own_lump", which is
+ * embedded in the FIFO structure). There is always at least one lump in
+ * the FIFO.
*
- * Once a lump has been allocated there is always one lump in the FIFO.
+ * The hold_ptr allows the get_ptr to move forward, but retaining the data in
+ * the FIFO until the hold_ptr is cleared. Can move the get_ptr back to the
+ * hold_ptr to reread the data.
*
- * The hold_mark allows the get_ptr to move forward, but retaining the data in
- * the FIFO until the hold_mark is cleared. Can move the get_ptr back to the
- * hold_mark to reread the data.
- *
- * The end_mark allows put_ptr to move forward, but the new data cannot be got
- * from the FIFO until the end_mark is cleared. Can discard the new data
- * and move the put_ptr back to the end_mark.
+ * The end_ptr allows put_ptr to move forward, but the new data cannot be got
+ * from the FIFO until the end_ptr is cleared. Can discard the new data
+ * and move the put_ptr back to the end_ptr.
*
* There are four lumps of interest:
*
@@ -70,32 +70,19 @@
*
* The following are expected to be true:
*
- * * set <=> at least one lump in the FIFO
- *
- * * as_one <=> set && get_lump == tail && !end_mark
- * => get_end moves with put_ptr
- *
- * * hold_mark => there is a hold mark & hold_ptr is valid
- * & head lump contains mark
- * !hold_mark => get_lump == head & hold_ptr == NULL
- *
- * * end_mark => there is an end_mark & end_end is valid
- * & end_lump contains mark
- * !end_mark => end_lump == tail & end_ptr == NULL
+ * * p_start == &get_ptr => no hold mark
+ * &hold_ptr => have hold mark
*
- * * put_ptr == get_ptr => FIFO empty -- unless hold_mark and
- * hold_ptr != get_ptr.
+ * * put_ptr == get_ptr => FIFO empty -- unless *p_start != get_ptr.
*
- * * put_end == tail->end -- at all times (NULL when no lumps)
+ * * put_end == tail->end -- at all times
*
* put_ptr >= tail->data ) otherwise something is broken
* put_ptr <= tail->end )
*
- * * get_end == get_lump->end -- when get_lump != end_lump
- * == end_end -- when get_lump == end_lump & end_mark set
- * <= put_ptr -- when get_lump == end_lump & no end_mark
- *
- * See note below on get_end and as_one flag.
+ * * p_get_end == &get_lump->end -- when get_lump != end_lump
+ * == &end_ptr -- when get_lump == end_lump & end mark set
+ * == &put_ptr -- when get_lump == end_lump & no end mark
*
* get_ptr >= get_lump->data ) otherwise something is broken
* get_ptr <= get_lump->end )
@@ -104,412 +91,334 @@
* put_ptr < put_end => space exists in the tail lump
* put_ptr > put_end => broken
*
- * * get_ptr == get_end => nothing to get from current get_lump
- * BUT if as_one, make sure that get_end == put_ptr
- * get_ptr < get_end => data exists in the current get_lump
- * get_ptr > get_end => broken
- *
- * Note that:
- *
- * * while get_ptr <= get_end can get stuff without worrying about other
- * pointers or moving between lumps etc. It is permissible to leave
- * get_ptr == get_end -- this will be tidied up on the next get operation,
- * or any other time vio_fifo_sync_get() is called. Leaving get_ptr in
- * that state delays the discard of the now empty lump, but has no other
- * real downside.
+ * * get_ptr == *p_get_end => nothing to get -- get_lump == end_lump
+ * get_ptr < *p_get_end => data exists in the current get_lump
+ * get_ptr > *p_get_end => broken
*
- * Similarly, while put_ptr <= put_end, can put stuff without worrying
- * about other pointers or moving between lumps etc.
+ * * p_end == &end_ptr -- when end mark set
+ * == &put_ptr -- when no end mark
*
- * When getting, if get_ptr == get_end, or require more data than is
- * immediately available, need to use vio_fifo_sync_get(), to do that.
- *
- * * the value of get_end depends on whether get_lump == end_lump, and then
- * whether there is an end_mark.
+ * Note that:
*
- * When get_lump == end_lump && !end_mark, then get_end may be out of date
- * because get_ptr has been advanced. This is dealt with by
- * vio_fifo_sync_get(), which uses the as_one flag to signal that it should
- * set get_end = put_ptr and then (re)check for anything to get.
+ * * while get_ptr < *p_get_end can get stuff without worrying about other
+ * pointers or moving between lumps etc.
*
- * The as_one flag is there to save a little work. Making sure that the
- * get_end is up to date can be done often when getting from the FIFO. So
- * the maintenance of the flag should be worth the effort.
+ * When get_ptr reaches *p_get_end, however, must move to the next lump,
+ * if possible, or collapse the pointers if have hit the put_ptr. Keeping
+ * the get_ptr honest in this way: (a) ensures that will always put at
+ * the beginning of a lump if possible; (b) simplifies the handling of
+ * hold_ptr et al (because get_ptr is never in the ambiguous position
+ * at the end of one lump, which is the same as the start of the next).
*
- * * some care must be taken to ensure that are not fooled by the
- * ambiguity of a pointer to the end of one lump and a pointer to the
- * start of the next -- these are really equal, but they don't look as if
- * they are !
+ * Similarly, while put_ptr < put_end, can put stuff without worrying
+ * about other pointers or moving between lumps etc. Will leave the
+ * put_ptr at the very end of the current lump if just fills it.
*
- * - put_ptr -- if at the end of the last lump there is no next lump !
+ * * the value of p_get_end depends on whether get_lump == end_lump, and
+ * then whether there is an end_ptr. But at any time, points to the end
+ * of what can be read by get_ptr without stepping between lumps etc.
*
- * When a new lump is added, the put_ptr advances to the
- * start of the new last lump.
+ * Note that get_ptr == p_get_end <=> is at the current end of the FIFO,
+ * because after any get operation, will advance to the next lump. If
+ * FIFO is empty after advancing the get_ptr, will reset the pointers
+ * back to the start of the then current (and only) lump.
*
- * - end_end -- when set from the put_ptr, this can be at the end of
- * the last lump, but as above, there is no next lump.
+ * * some care must be taken to ensure that if the fifo is empty, the
+ * pointers will be at the start of one empty lump.
*
- * When a new lump is added, if the end_end is at the
- * end of the last lump, it is moved to the start of the
- * new last lump (along with the out_ptr).
+ * In this context, empty means nothing between *p_start and put_ptr.
+ * Noting that *p_start is &hold_ptr or &get_ptr, depending on whether
+ * there is a hold mark or not. (If *p_start == put_ptr, there may be
+ * an end mark, but it must be end_ptr == put_ptr !)
*
- * So... end_end will never be ambiguous.
+ * - get_ptr -- as above, if this hits *p_get_end, must:
*
- * - get_ptr -- this can be ambiguous.
+ * * step to the next lump, if there is one, and,
+ * unless something is held behind the get_ptr,
+ * release the lump just stepped from.
*
- * When getting bytes, if the segment get_ptr..get_end
- * is sufficient, then nothing else is required.
+ * * if has hit put_ptr, reset pointers -- unless there
+ * is something held behind the get_ptr.
*
- * Otherwise, vio_fifo_sync_get() will sort things out,
- * including resetting all pointers if the FIFO has been
- * emptied.
+ * - put_ptr -- is always somewhere in the tail lump.
*
- * - hold_ptr -- when set from get_ptr this could be at the end of the
- * first lump -- but when vio_fifo_sync_get() is called,
- * that will be spotted and sorted out.
+ * - end_ptr -- when a new lump is added, if the end_ptr is at the
+ * end of the last lump, it is moved to the start of the
+ * new last lump (along with the put_ptr).
*
- * If get_ptr is set from an ambiguous hold_ptr, that is
- * also taken care of by the next vio_fifo_sync_get().
+ * If the end_ptr is equal to the put_ptr and the get_ptr
+ * hits it, if the pointers are reset, the end_ptr will be
+ * reset along with the put_ptr.
*
- * When doing things with hold_ptr, does a number of
- * vio_fifo_sync_get() operations, so the hold_ptr should
- * not, in practice, be ambiguous.
+ * If the put_ptr is reset back to the end_ptr, need to
+ * see if the FIFO is empty, and reset pointers if it is.
*
- * * Before the first lump is allocated the FIFO appears empty (of course)
- * but may have hold_mark and/or end_mark set, and these work as expected.
- */
-
-/*==============================================================================
- * Initialisation, allocation and freeing of FIFO and lumps thereof.
+ * - hold_ptr -- because the pointers are reset whenever the FIFO
+ * becomes empty, when hold_ptr is set, it will be at
+ * the start of an empty FIFO, or somewhere in a not-
+ * empty one. When a hold_ptr is cleared, the get_ptr
+ * may be equal to the put_ptr, and pointers must be
+ * reset.
*/
+inline static void vio_fifo_set_get_ptr(vio_fifo vff, vio_fifo_lump lump,
+ char* ptr) ;
+inline static void vio_fifo_set_get_end(vio_fifo vff) ;
+inline static void vio_fifo_release_upto(vio_fifo vff, vio_fifo_lump upto) ;
+static void vio_fifo_release_lump(vio_fifo vff, vio_fifo_lump lump) ;
/*------------------------------------------------------------------------------
- * Return default size, or given size rounded up to 128 byte boundary
+ * Test whether there is a hold mark.
*/
-static size_t
-vio_fifo_size(size_t size)
+inline static bool
+vio_fifo_have_hold_mark(vio_fifo vff)
{
-#if VIO_FIFO_DEBUG
-#warning VIO_FIFO_DEBUG and 29 byte lumps !
- return 29 ;
-#else
- if (size == 0)
- return 4096 ;
- else
- return ((size + 128 - 1) / 128) * 128 ;
-#endif
+ return vff->p_start == &vff->hold_ptr ;
} ;
/*------------------------------------------------------------------------------
- * Set and return true end of lump.
- *
- * End of lump can be set short of true end when putting stuff, if wish to
- * move to next lump early (eg if not enough room left in current lump).
- *
- * When reusing a lump, need to restore the true lump end.
+ * Test whether there is an end mark.
*/
-static inline char*
-vio_fifo_true_lump_size(vio_fifo_lump lump)
+inline static bool
+vio_fifo_have_end_mark(vio_fifo vff)
{
- return lump->end = lump->data + lump->size ;
+ return vff->p_end == &vff->end_ptr ;
} ;
-/*==============================================================================
- * Initialise VTY I/O FIFO -- allocating if required.
- */
-extern vio_fifo
-vio_fifo_init_new(vio_fifo vff, size_t size)
-{
- if (vff == NULL)
- vff = XCALLOC(MTYPE_VIO_FIFO, sizeof(vio_fifo_t)) ;
- else
- memset(vff, 0, sizeof(vio_fifo_t)) ;
-
- /* Zeroising the the vio_fifo_t has set:
- *
- * base -- base pair, both pointers NULL => list is empty
- *
- * set -- false -- nothing set, yet.
- * as_one -- false -- get_lump != tail or end_mark
- * hold_mark -- false -- no hold mark
- * end_mark -- false -- no end mark
- *
- * hold_ptr -- NULL no hold_mark
- *
- * get_lump -- NULL )
- * get_ptr -- NULL ) no lump to get anything from
- * get_end -- NULL ) get_ptr -- get_end => nothing left in current lump
- *
- * end_lump -- NULL no lump at end of what can get
- * end_end -- NULL no end_mark
- *
- * put_ptr -- NULL ) no lump to put anything into
- * put_end -- NULL ) put_ptr == put_end => no room in current lump
- *
- * size -- 0 no size set for lumps (yet)
- *
- * spare -- NULL no spare lump
- */
- confirm(VIO_FIFO_INIT_ALL_ZEROS) ;
-
- if (size != 0)
- vff->size = vio_fifo_size(size) ;
-
- VIO_FIFO_DEBUG_VERIFY(vff) ;
-
- return vff ;
-}
-
/*------------------------------------------------------------------------------
- * Free contents of given FIFO, and free FIFO structure as well, if required.
- *
- * Does nothing if given a NULL pointer -- must already have been freed !
+ * The FIFO is empty, with one lump -- reset all pointers.
*
- * If does not free the FIFO structure, resets it all empty, keeping the
- * current size setting.
+ * Preserves and hold mark or end mark -- so no need to change p_start or p_end.
*
- * Frees *all* FIFO lumps.
+ * HOWEVER: does not set p_get_end -- so if get_lump or end_lump or p_end have
+ * changed, then must also call vio_fifo_set_get_end().
*
- * See also: vio_fifo_reset_keep(vio_fifo)
- * vio_fifo_reset_free(vio_fifo)
+ * ALSO: does not set put_end -- so if the tail lumps has changed, that must
+ * be updated.
*/
-extern vio_fifo
-vio_fifo_reset(vio_fifo vff, free_keep_b free_structure)
+inline static void
+vio_fifo_reset_ptrs(vio_fifo vff)
{
- vio_fifo_lump lump ;
-
- if (vff == NULL)
- return NULL ;
-
- while (ddl_pop(&lump, vff->base, list) != NULL)
- XFREE(MTYPE_VIO_FIFO_LUMP, lump) ;
+ char* ptr = ddl_tail(vff->base)->data ;
- if (vff->spare != NULL)
- XFREE(MTYPE_VIO_FIFO_LUMP, vff->spare) ;
-
- confirm(free_it == true) ;
-
- if (free_structure)
- XFREE(MTYPE_VIO_FIFO, vff) ; /* sets vff = NULL */
- else
- vio_fifo_init_new(vff, vff->size) ;
+ if (vio_fifo_debug)
+ assert(ddl_head(vff->base) == ddl_tail(vff->base)) ;
- return vff ;
+ vff->hold_ptr = ptr ;
+ vff->get_ptr = ptr ;
+ vff->end_ptr = ptr ;
+ vff->put_ptr = ptr ;
} ;
/*------------------------------------------------------------------------------
- * The FIFO has one lump -- set all pointers.
+ * This is called *iff* get_ptr >= *p_get_end -- and preferably only after
+ * it has been adjusted forwards by at least 1 (but that is not required).
*
- * Preserves end_mark -- setting to new put_ptr position
- * Preserves hold_mark -- setting to new put_ptr position
- *
- * Sets as_one if no end_mark.
+ * If there is anything available to be got, adjust get_ptr and/or get_end
+ * in order to be able to get it -- discarding lumps as required.
*/
-inline static void
-vio_fifo_ptr_set(vio_fifo vff, vio_fifo_lump lump)
+Private void
+vio_fifo_sync_get(vio_fifo vff)
{
- vff->as_one = !vff->end_mark ;
+ if (vio_fifo_debug)
+ assert(vff->get_ptr == *vff->p_get_end) ;
- vff->put_ptr = lump->data ;
- vff->put_end = vio_fifo_true_lump_size(lump) ;
+ if (vff->get_lump == vff->end_lump)
+ {
+ if (vio_fifo_debug)
+ assert(vff->get_ptr == *vff->p_end) ;
- vff->hold_ptr = vff->hold_mark ? vff->put_ptr : NULL ;
+ /* We are in the end_lump, and there is nothing more to be read.
+ *
+ * If have reached the put_ptr, then unless there is something held
+ * behind the get_ptr, the fifo is completely empty, and pointers can
+ * be reset to the start of the end_lump (which is the only lump).
+ *
+ * p_start == &hold_ptr or &get_ptr, so can check for empty in one test.
+ */
+ if (*vff->p_start == vff->put_ptr)
+ vio_fifo_reset_ptrs(vff) ;
+ }
+ else
+ {
+ /* Good news, can advance the get_ptr
+ *
+ * Step the get_ptr to the start of the next lump, and if no hold mark,
+ * discard any lumps which precede the new get_lump.
+ */
+ vio_fifo_lump get_lump ;
- vff->get_lump = lump ;
- vff->get_ptr = vff->put_ptr ;
- vff->get_end = vff->put_ptr ;
+ if (vio_fifo_debug)
+ {
+ assert(vff->get_lump != vff->end_lump) ;
+ assert(vff->get_ptr == vff->get_lump->end) ;
+ } ;
- vff->end_lump = lump ;
- vff->end_end = vff->end_mark ? vff->put_ptr : NULL ;
+ get_lump = ddl_next(vff->get_lump, list) ;
+ vio_fifo_set_get_ptr(vff, get_lump, get_lump->data) ;
+
+ if (!vio_fifo_have_hold_mark(vff))
+ vio_fifo_release_upto(vff, get_lump) ;
+ } ;
} ;
/*------------------------------------------------------------------------------
- * The FIFO is empty, with one lump -- reset all pointers.
- *
- * Preserves end_mark -- setting to new put_ptr position
- * Preserves hold_mark -- setting to new put_ptr position
- *
- * Sets as_one if no end_mark.
+ * Set get_lump/get_ptr and p_get_end to suit.
*/
inline static void
-vio_fifo_ptr_reset(vio_fifo vff, vio_fifo_lump lump)
+vio_fifo_set_get_ptr(vio_fifo vff, vio_fifo_lump lump, char* ptr)
{
- assert(vff->set) ;
- assert(lump == ddl_tail(vff->base)) ; /* must be tail */
- assert(lump == ddl_head(vff->base)) ; /* and must be head */
+ vff->get_lump = lump ;
+ vff->get_ptr = lump->data ;
- vio_fifo_ptr_set(vff, lump) ;
+ vio_fifo_set_get_end(vff) ;
} ;
/*------------------------------------------------------------------------------
- * Synchronise get_end and put_ptr (if required)
- *
- * When in the same lump, the get_end and the put_ptr should be the same. But
- * maintaining that every time something is put into the buffer is a pain, so
- * we allow the put_ptr to get ahead, and re-synchronise when get_ptr hits
- * get_end, or any other time we need the pointers to be straight.
- *
- * The as_one flag takes a little maintenance... it means:
- *
- * (get_lump == tail) && set && !end_mark
- *
- * If get_ptr is at the end of what can be got from the current lump, advances
- * to the next lump if possible, releasing anything that can be released.
- *
- * If the FIFO is empty (with one lump), will crash all pointers down to start
- * of current lump. The FIFO is empty if get_ptr == put_ptr, and there are no
- * bytes held before the get_ptr.
- *
- * NB: object of the hold_mark is to allow users of the FIFO to store pointers
- * to sections of the FIFO returned by vio_fifo_get_lump() and stepped
- * over by vio_fifo_got_upto(). Note that where there is nothing to
- * read vio_fifo_get_lump() returns NULL -- so do not have to preserve
- * the hold_ptr when hold_ptr == get_ptr (== end_end) == put_ptr -- that
- * is, if hold_ptr == get_ptr, we can move the hold_ptr around with the
- * get_ptr.
+ * Set the p_get_end depending on whether the get_lump == end_lump, or not.
*
- * Can reach empty state without realising it, because the "get" stuff is not
- * required to check every time a byte is read -- in fact, it is not necessary
- * to check until cannot get anything because get_ptr == get_end.
- *
- * NB: with an end_mark there is the ambiguous position at the end of a
- * lump -- which is the same as the start of the next lump, if any.
- *
- * Elsewhere we advance the end_end if it was at the very end of the FIFO
- * and we advance the put_ptr to a new lump. But we cope here in any
- * case.
- *
- * Returns: true <=> there is something in the (now) current get_lump.
- * false <=> there is nothing else to be got (though if there is an
- * end_mark, there may be stuff beyond that).
+ * This must be called if the get_lump or the end_lump are changed, or if
+ * p_end changes.
*/
-static bool vio_fifo_sync_get_next(vio_fifo vff) ;
-static void vio_fifo_release_head(vio_fifo vff, vio_fifo_lump lump) ;
-
-inline static bool
-vio_fifo_sync_get(vio_fifo vff)
+inline static void
+vio_fifo_set_get_end(vio_fifo vff)
{
- if (vff->as_one) /* false if !vff->set */
- vff->get_end = vff->put_ptr ;
-
- if (vff->get_ptr < vff->get_end) /* both NULL if !vff->set */
- return true ; /* have at least one byte */
-
- return vio_fifo_sync_get_next(vff) ;
+ vff->p_get_end = (vff->get_lump == vff->end_lump) ? vff->p_end
+ : &vff->get_lump->end ;
} ;
/*------------------------------------------------------------------------------
- * See if fifo really is or is not empty (get_ptr == end_end or == put_ptr).
- *
- * Used by vio_fifo_empty(). Called iff get_ptr >= get_end !
+ * Release all lumps upto (but excluding) the given lump.
*
- * So need to vio_fifo_sync_get() and test again against end_end & put_ptr.
+ * NB: takes no notice of hold_ptr or anything else.
*/
-Private bool
-vio_fifo_do_empty(vio_fifo vff)
+inline static void
+vio_fifo_release_upto(vio_fifo vff, vio_fifo_lump upto)
{
- return ! vio_fifo_sync_get(vff) ;
+ vio_fifo_lump lump ;
+ while (ddl_head(vff->base) != upto)
+ vio_fifo_release_lump(vff, ddl_pop(&lump, vff->base, list)) ;
} ;
-/*------------------------------------------------------------------------------
- * Set a new get_lump/get_ptr/get_end set. And set as_one to suit.
+/*==============================================================================
+ * Initialisation, allocation and freeing of FIFO and lumps thereof.
*/
-inline static void
-vio_fifo_set_get_ptr(vio_fifo vff, void* ptr, vio_fifo_lump lump)
-{
- vff->get_lump = lump ;
- vff->get_ptr = ptr ;
-
- if (lump != vff->end_lump)
- {
- vff->get_end = lump->end ;
- vff->as_one = false ;
- }
- else if (vff->end_mark)
- {
- vff->get_end = vff->end_end ;
- vff->as_one = false ;
- }
- else
- {
- vff->get_end = vff->put_ptr ;
- vff->as_one = true ;
- } ;
-} ;
/*------------------------------------------------------------------------------
- * Move on to next lump to get stuff from.
+ * Allocate and initialise a new FIFO.
+ *
+ * The size given is the size for all lumps in the FIFO. 0 => default size.
*
- * For use by vio_fifo_sync_get() *ONLY*.
+ * Size is rounded up to a 128 byte boundary.
*
- * Asserts that (vff->get_ptr == vff->get_end) and assumes that if as_one, then
- * get_end == put_ptr !
+ * Once allocated and initialised, the FIFO contains one lump, and if it
+ * grows to more than one, will retain a spare lump once it shrinks again.
*
- * Returns: true <=> at least one byte in FIFO available to get.
+ * Keeping a pair of lumps allows the get_ptr to lag behind the put_ptr by
+ * about a lump full, without requiring repeated memory allocation. Also,
+ * vio_fifo_write_nb() can be asked to write only lumps -- so if called
+ * regularly while putting stuff to a FIFO, will write entire lumps at once.
*/
-static bool
-vio_fifo_sync_get_next(vio_fifo vff)
+extern vio_fifo
+vio_fifo_new(ulen size)
{
- bool hold_empty ;
+ vio_fifo vff ;
+ ulen total_size ;
+
+ if (size == 0)
+ size = VIO_FIFO_DEFAULT_LUMP_SIZE ;
- assert(vff->get_ptr == vff->get_end) ;
+ size = ((size + 128 - 1) / 128) * 128 ;
- VIO_FIFO_DEBUG_VERIFY(vff) ;
+ if (vio_fifo_debug)
+ size = 29 ;
- if (!vff->set)
- return false ; /* quit before get into any trouble */
+ total_size = offsetof(struct vio_fifo, own_lump->data[size]) ;
- /* Worry about whether there is anything held.
+ vff = XCALLOC(MTYPE_VIO_FIFO, total_size) ;
+
+ /* Zeroising the the vio_fifo_t has set:
+ *
+ * base -- base pair, both pointers NULL => list is empty
+ *
+ * p_start -- X -- see vio_fifo_ptr_set()
+ *
+ * hold_ptr -- NULL -- not relevant until hold mark is set
+ *
+ * get_lump -- X )
+ * get_ptr -- X ) -- see vio_fifo_ptr_set()
+ * p_get_end -- X )
+ *
+ * end_lump -- X -- see vio_fifo_ptr_set()
+ *
+ * end_ptr -- NULL -- not relevant until hold mark is set
+ *
+ * put_ptr -- X )
+ * put_end -- X ) -- see vio_fifo_ptr_set()
+ * p_end -- X )
+ *
+ * size -- X -- set below
*
- * NB: we know that at this point the get_ptr == get_end, so is at the end
- * of the current get_lump. The hold_ptr cannot be ahead of get_ptr,
- * so the test hold_ptr == get_ptr is sufficient to detect that there
- * is nothing, in fact, held.
+ * spare -- NULL -- no spare lump
+ *
+ * own_lump -- all zeros: list -- pointers NULL, set below
+ * end -- set below
*/
- hold_empty = !vff->hold_mark || (vff->hold_ptr == vff->get_ptr) ;
+ vff->size = size ;
+ vff->own_lump->end = vff->own_lump->data + vff->size ;
- /* If we are not at the end_lump, step forward, discarding current
- * lump unless hold_mark.
- */
- if (vff->get_lump != vff->end_lump)
- {
- vio_fifo_lump next ;
- next = ddl_next(vff->get_lump, list) ;
+ if (vio_fifo_debug)
+ assert(vff->own_lump->end == ((char*)vff + total_size)) ;
- vio_fifo_set_get_ptr(vff, next->data, next) ;
+ ddl_append(vff->base, vff->own_lump, list) ;
- if (hold_empty)
- {
- vio_fifo_release_head(vff, next) ;
+ vff->p_start = &vff->get_ptr ;
- /* If there is a hold_mark, then had hold_ptr == get_ptr
- * and this is where we keep hold_ptr & get_ptr in sync.
- */
- if (vff->hold_mark)
- vff->hold_ptr = vff->get_ptr ;
- } ;
+ vff->get_lump = vff->own_lump ;
+ vff->get_ptr = vff->own_lump->data ;
+ vff->p_get_end = &vff->put_ptr ;
- /* Return the get state now */
- if (vff->get_ptr < vff->get_end)
- return true ;
- } ;
+ vff->end_lump = vff->own_lump ;
- /* Still have get_ptr == get_end => nothing more to get.
- *
- * Check now for empty FIFO, and reset all pointers if that is the case.
- */
- if ((vff->get_ptr == vff->put_ptr) && hold_empty)
+ vff->put_ptr = vff->own_lump->data ;
+ vff->put_end = vff->own_lump->end ;
+
+ vff->p_end = &vff->put_ptr ;
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+
+ return vff ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Free contents of given FIFO and the FIFO structure as well.
+ *
+ * Does nothing if given a NULL pointer -- must already have been freed !
+ *
+ * Returns: NULL
+ */
+extern vio_fifo
+vio_fifo_free(vio_fifo vff)
+{
+ if (vff != NULL)
{
- if (vff->hold_mark)
- assert(vff->hold_ptr == vff->get_ptr) ;
+ vio_fifo_lump lump ;
- if (vff->end_mark)
- assert(vff->end_end == vff->put_ptr) ;
+ lump = vff->spare ;
+ vff->spare = NULL ;
- vio_fifo_ptr_reset(vff, vff->end_lump) ;
- }
+ do
+ {
+ if (lump != vff->own_lump)
+ XFREE(MTYPE_VIO_FIFO_LUMP, lump) ; /* accepts lump == NULL */
- return false ; /* nothing to get */
+ ddl_pop(&lump, vff->base, list) ;
+ }
+ while (lump != NULL) ;
+
+ XFREE(MTYPE_VIO_FIFO, vff) ;
+ } ;
+
+ return NULL ;
} ;
/*------------------------------------------------------------------------------
@@ -517,214 +426,128 @@ vio_fifo_sync_get_next(vio_fifo vff)
*
* If required, clears any hold mark and/or end mark.
*
- * Keeps one FIFO lump. (Frees everything else, including any spare.)
+ * Keeps one spare lump.
*
* Does nothing if there is no FIFO !
*/
extern void
vio_fifo_clear(vio_fifo vff, bool clear_marks)
{
+ vio_fifo_lump lump ;
+
if (vff == NULL)
return ;
VIO_FIFO_DEBUG_VERIFY(vff) ;
- vff->as_one = vff->set ;
- if (clear_marks)
- {
- vff->hold_mark = false ; /* Discard marks */
- vff->end_mark = false ;
- } ;
+ lump = ddl_tail(vff->base) ;
- if (vff->set)
- {
- vio_fifo_lump lump ;
+ vio_fifo_release_upto(vff, lump) ;
- while (1)
- {
- lump = ddl_head(vff->base) ;
- if (lump == ddl_tail(vff->base))
- break ;
+ vff->get_lump = lump ;
+ vff->end_lump = lump ;
- ddl_pop(&lump, vff->base, list) ;
- XFREE(MTYPE_VIO_FIFO_LUMP, lump) ;
- } ;
+ vio_fifo_reset_ptrs(vff) ;
- vio_fifo_ptr_reset(vff, lump) ;
+ if (clear_marks)
+ {
+ vff->p_start = &vff->get_ptr ;
+ vff->p_end = &vff->put_ptr ;
} ;
- if (vff->spare != NULL)
- XFREE(MTYPE_VIO_FIFO_LUMP, vff->spare) ; /* sets vff->spare = NULL */
+ vff->p_get_end = vff->p_end ;
VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
/*------------------------------------------------------------------------------
- * See how much room there is in the FIFO.
- *
- * If no lumps have been allocated, returns the size of the lump that would
- * allocate.
- *
- * Otherwise, returns the amount of space available *without* allocating any
- * further lumps.
- *
- * Returns: room available as described
- */
-extern size_t
-vio_fifo_room(vio_fifo vff)
-{
- if (vff->set)
- return vff->put_end - vff->put_ptr ;
- else
- return vff->size ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Need a new lump to put stuff into.
+ * Add a new lump to put stuff into -- work-horse for putting to the FIFO.
*
* Call when (vff->put_ptr >= vff->put_end) -- asserts that they are equal.
*
- * If the FIFO is, in fact, empty but with at least one lump, then does not
- * allocate anything more, but releases all lumps but the last lump and then
- * resets all pointers to the start of that lump.
+ * The FIFO cannot be empty -- if it were, the pointers would have been reset,
+ * and could not be vff->put_ptr >= vff->put_end !!
*
- * Otherwise, allocates a new lump (or reuses the spare) to the requested size,
- * and updates all pointers as required. (Allocates to vff->size if
- * requested size is zero.)
+ * Allocates a new lump (or reuses the spare) and updates the put_ptr.
*
- * NB: if there is an end_mark, makes sure that it advances with the put_ptr
- * if currently end_end == the put_ptr.
+ * If the end_ptr and the put_ptr were equal, then advances that too, which
+ * ensures that the end_ptr is not ambiguous.
+
+ * If the get_ptr and the put_ptr were equal, then advances that too, which
+ * ensures that the get_ptr is not ambiguous. This can be the case if there
+ * is a hold_ptr.
*/
Private void
-vio_fifo_lump_new(vio_fifo vff, size_t size)
+vio_fifo_add_lump(vio_fifo vff)
{
vio_fifo_lump lump ;
- size_t std_size ;
- passert(vff->put_ptr == vff->put_end) ; /* must be end of tail lump
- (or both NULL) */
+ assert(vff->put_ptr == vff->put_end) ; /* must be end of tail lump */
+ assert(vff->put_ptr != *vff->p_start) ; /* cannot be empty ! */
+
VIO_FIFO_DEBUG_VERIFY(vff) ;
- /* First, make sure that the get side is synchronised, which may advance
- * various pointers, release lumps and possibly reset now empty FIFO.
- *
- * If synchronising the get side does not yield space, then the FIFO is
- * either not set or it has something in it (including held stuff).
+ /* If we can use the spare, do so, otherwise make a new one and
+ * add to the end of the FIFO.
*/
- vio_fifo_sync_get(vff) ;
-
- if (vff->put_ptr < vff->put_end)
- return ; /* Done if have created space */
-
- /* If we can use the spare, do so, otherwise make it to size */
lump = vff->spare ;
vff->spare = NULL ;
- std_size = vio_fifo_size(vff->size) ; /* normalised standard */
+ if (lump == NULL)
+ {
+ ulen lump_size = offsetof(vio_fifo_lump_t, data[vff->size]) ;
- if (size <= std_size)
- size = std_size ; /* use standard as a minimum */
- else
-#if VIO_FIFO_DEBUG
- size |= 3 ; /* most of the time a little bigger */
-#else
- size = vio_fifo_size(size) ; /* normalise requested size */
-#endif
+ lump = XMALLOC(MTYPE_VIO_FIFO_LUMP, lump_size) ;
+ lump->end = (char*)lump + lump_size ;
- if ((lump == NULL) || (lump->size < size))
- {
- /* If there was no spare, lump == NULL and XREALLOC == XMALLOC.
- * If there was a spare that was too small, better extend that than
- * keep a sub-standard spare.
- */
- lump = XREALLOC(MTYPE_VIO_FIFO_LUMP, lump,
- offsetof(vio_fifo_lump_t, data[size])) ;
- lump->size = size ;
- lump->end = lump->data + size ;
+ if (vio_fifo_debug)
+ assert(lump->end == (lump->data + vff->size)) ;
} ;
ddl_append(vff->base, lump, list) ;
- /* If not just allocated the first lump, set the put_ptr and normalise any
- * end_mark or update end_lump.
+ /* Allocated new lump on the end of FIFO.
+ *
+ * If the get_ptr == put_ptr, advance the get_ptr. If there is an end_ptr,
+ * it must be == put_ptr, and is about to advance too.
+ *
+ * If put_ptr == *p_end, advance the end_lump and the end_ptr. If there is
+ * no end_mark, then p_end == &put_ptr, and the end_lump must follow the
+ * put_ptr. If there is an end_mark, then p_end == &end_ptr, and that must
+ * follow the put_ptr if they are equal.
*
- * If is first block to be allocated, set all pointers, taking into account
- * any end_mark and/or hold_mark.
+ * The get_lump may or may not have been the end_lump, and that may or may
+ * not have changed. Simplest thing is to set p_get_end to what it should
+ * be now.
*/
- if (vff->set)
+ if (vff->get_ptr == vff->put_ptr)
{
- /* Allocated new lump on the end of a not-empty fifo.
- *
- * Have to watch out for cases where the get_ptr and/or end_end are
- * equal to the put_ptr, which is about to move to the start of a new
- * lump, so as to avoid ambiguity !
- */
+ if (vio_fifo_debug)
+ assert(vio_fifo_have_hold_mark(vff)) ;
- if (vff->get_ptr == vff->put_ptr)
- {
- /* If the fifo is empty, the vio_fifo_sync_get() above will have
- * spotted it. So can only get here iff there is something held in
- * the fifo behind the get_ptr.
- *
- * If was as_one, is still as_one.
- *
- * If was not as_one then must have end_mark with end_end == put_ptr,
- * which will be dealt with below.
- */
- assert(vff->hold_mark && (vff->get_ptr != vff->hold_ptr)) ;
-
- vff->get_ptr = lump->data ;
- vff->get_end = lump->data ;
- vff->get_lump = lump ;
- }
- else
- {
- /* If were as_one, then will no longer be, because put_ptr is about
- * to advance to the start of the new lump.
- */
- vff->as_one = false ;
- } ;
-
- if (vff->end_mark)
- {
- assert(!vff->as_one) ;
-
- /* The end_end follows the put_ptr iff they are equal
- *
- * If the get_ptr also equals the put_ptr, it has already advanced.
- */
- if (vff->end_end == vff->put_ptr)
- {
- vff->end_end = lump->data ;
- vff->end_lump = lump ;
- } ;
- }
- else
- {
- /* No end_mark => end_lump simply follows the put_ptr. */
- vff->end_lump = lump ;
- } ;
+ vff->get_lump = lump ;
+ vff->get_ptr = lump->data ;
+ } ;
- vff->put_ptr = lump->data ;
- vff->put_end = vio_fifo_true_lump_size(lump) ;
- }
- else
+ if (vff->put_ptr == *vff->p_end)
{
- /* Allocated lump for previously empty fifo -- set all pointers to the
- * start of the lump, except for put_end.
- */
- vff->set = true ;
- vio_fifo_ptr_set(vff, lump) ;
+ vff->end_lump = lump ;
+ vff->end_ptr = lump->data ; /* no effect if no end_mark */
} ;
+ vff->put_ptr = lump->data ;
+ vff->put_end = lump->end ;
+
+ vio_fifo_set_get_end(vff) ;
+
VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
/*------------------------------------------------------------------------------
* Release the given lump, provided it is neither get_lump nor end_lump.
*
- * If don't have a spare lump, keep this one. Otherwise, keep larger of
- * this and current spare.
+ * If don't have a spare lump, keep this one.
+ * If do have a spare lump, discard this one, unless it is "own_lump".
*/
static void
vio_fifo_release_lump(vio_fifo vff, vio_fifo_lump lump)
@@ -733,63 +556,17 @@ vio_fifo_release_lump(vio_fifo vff, vio_fifo_lump lump)
assert(lump != vff->get_lump) ;
assert(lump != vff->end_lump) ;
- if (vff->spare != NULL)
+ if (vff->spare == NULL)
+ vff->spare = lump ;
+ else
{
- vio_fifo_lump free ;
-
- free = vff->spare ;
-
- if (free->size > lump->size)
+ if (lump == vff->own_lump)
{
- free = lump ;
- lump = vff->spare ;
+ lump = vff->spare ; /* free the spare instead */
+ vff->spare = vff->own_lump ;
} ;
- XFREE(MTYPE_VIO_FIFO_LUMP, free) ;
- } ;
-
- vff->spare = lump ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Release lumps from head up to, but not including, given lump.
- *
- * NB: must be "set" and must not attempt to release the get_lump or the
- * end_lump.
- *
- * So MUST advance at least the get_lump before calling this.
- *
- * It is the caller's responsibility to update get and/or hold pointers.
- */
-static void
-vio_fifo_release_head(vio_fifo vff, vio_fifo_lump upto)
-{
- assert(vff->set) ;
-
- while (upto != ddl_head(vff->base))
- {
- vio_fifo_lump lump ;
- vio_fifo_release_lump(vff, ddl_pop(&lump, vff->base, list)) ;
- } ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Release lumps from tail back to, but not including, given lump.
- *
- * NB: must be "set" and must not attempt to release the get_lump or the
- * end_lump.
- *
- * It is the caller's responsibility to update end and/or put pointers.
- */
-static void
-vio_fifo_release_tail(vio_fifo vff, vio_fifo_lump backto)
-{
- assert(vff->set) ;
-
- while (backto != ddl_tail(vff->base))
- {
- vio_fifo_lump lump ;
- vio_fifo_release_lump(vff, ddl_crop(&lump, vff->base, list)) ;
+ XFREE(MTYPE_VIO_FIFO_LUMP, lump) ;
} ;
} ;
@@ -801,16 +578,16 @@ vio_fifo_release_tail(vio_fifo vff, vio_fifo_lump backto)
* Put 'n' bytes -- allocating as required.
*/
extern void
-vio_fifo_put_bytes(vio_fifo vff, const char* src, size_t n)
+vio_fifo_put_bytes(vio_fifo vff, const char* src, ulen n)
{
VIO_FIFO_DEBUG_VERIFY(vff) ;
while (n > 0)
{
- size_t take ;
+ ulen take ;
if (vff->put_ptr >= vff->put_end)
- vio_fifo_lump_new(vff, 0) ; /* traps put_ptr > put_end */
+ vio_fifo_add_lump(vff) ; /* traps put_ptr > put_end */
take = (vff->put_end - vff->put_ptr) ;
if (take > n)
@@ -853,105 +630,42 @@ vio_fifo_printf(vio_fifo vff, const char* format, ...)
* Returns: >= 0 -- number of bytes written
* < 0 -- failed (unlikely though that is)
*
- * NB: does not extend an existing lump in order to make things fit, but
- * splits the result across two lumps. This ensures that at all times
- * pointers into existing lumps are stable -- so pointer returned by
- * vio_fifo_get_lump(), for example, cannot be upset !
+ * NB: uses qfs_vprintf(qfs, format, va), which allows the result to be
+ * collected a section at a time, if required. With reasonable size
+ * lumps, expect to need no more than two sections, and then only
+ * occasionally.
*/
extern int
-vio_fifo_vprintf(vio_fifo vff, const char *format, va_list args)
+vio_fifo_vprintf(vio_fifo vff, const char *format, va_list va)
{
- va_list ac ;
- int len ;
- int have ;
- int had ;
- int need ;
- char* last ;
+ qf_str_t qfs ;
+ ulen done ;
if (vff == NULL)
return 0 ;
VIO_FIFO_DEBUG_VERIFY(vff) ;
- /* First the simple way.
- *
- * Note that vsnprintf() returns the length of what it would like to
- * have produced, if it had the space. That length does not include
- * the trailing '\0'. In the meantime, it has output as much as it
- * can, with a trailing '\0'.
- */
- assert(vff->put_ptr <= vff->put_end) ;
-
- have = vff->put_end - vff->put_ptr ; /* what can do in current lump
- if any. */
- va_copy(ac, args) ;
- len = vsnprintf(vff->put_ptr, have, format, ac) ;
- va_end(ac) ;
-
- if ((len < have) || (len == 0)) /* OK, or failed ! */
+ done = 0 ;
+ do
{
- if (len > 0)
- vff->put_ptr += len ; /* advance put_ptr as required */
-
- return len ;
- } ;
-
- /* Now know that we need len + 1 bytes in all to complete the task, and
- * that it has written have - 1 bytes to the existing lump (if any).
- *
- * Also, len > 0.
- *
- * Allocate a new lump in which we can write the entire result, even if
- * that is a non-standard size.
- */
- need = len + 1 ; /* need includes the '\0' */
- had = have ;
-
- if (had > 0)
- vff->put_ptr += had ; /* step to the end */
- last = vff->put_ptr ; /* point at end of lump (NULL if none) */
-
- vio_fifo_lump_new(vff, need) ;/* new lump to do it all */
-
- have = vff->put_end - vff->put_ptr ;
- assert(have >= need) ; /* have >= 2 */
-
- /* We really expect to get the same result a second time ! */
- va_copy(ac, args) ;
- len = vsnprintf(vff->put_ptr, have, format, ac) ;
- va_end(ac) ;
+ ulen did ;
- /* Since have >= what previously said it needed, things have gone
- * badly wrong if the new len is >= have.
- *
- * Also, things have gone badly wrong if new len is < what previously
- * had, which was then not enough !
- *
- * Also, things have gone badly wrong if new len == 0, because previously
- * it was > 0 !
- */
- if ((len >= have) || (len < had) || (len == 0))
- return (len < 0) ? len : -1 ;
+ if (vff->put_ptr >= vff->put_end)
+ vio_fifo_add_lump(vff) ; /* traps put_ptr > put_end */
- /* Move result around if required -- len >= had */
- have = len ;
- if (had > 0)
- {
- char* frag ;
- frag = vff->put_ptr + had ; /* first character to keep */
- *(last - 1) = *(frag - 1) ; /* replace the '\0' */
+ qfs_init_offset(qfs, vff->put_ptr, vff->put_end - vff->put_ptr, done) ;
- have -= had ; /* amount to keep */
- if (have > 0)
- memmove(vff->put_ptr, frag, have) ;
- } ;
+ did = qfs_vprintf(qfs, format, va) ;
- /* Advance the put_ptr past what we have in the new lump. */
- vff->put_ptr += have ;
+ done += did ;
+ vff->put_ptr += did ;
+ }
+ while (qfs_overflow(qfs) != 0) ;
VIO_FIFO_DEBUG_VERIFY(vff) ;
- return len ;
+ return done ;
} ;
/*------------------------------------------------------------------------------
@@ -972,9 +686,11 @@ vio_fifo_vprintf(vio_fifo vff, const char *format, va_list args)
* something, error or EOF.
*/
extern int
-vio_fifo_read_nb(vio_fifo vff, int fd, uint request)
+vio_fifo_read_nb(vio_fifo vff, int fd, ulen request)
{
- size_t total ;
+ ulen total ;
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
total = 0 ;
@@ -984,7 +700,7 @@ vio_fifo_read_nb(vio_fifo vff, int fd, uint request)
if (vff->put_ptr >= vff->put_end)
{
- vio_fifo_lump_new(vff, 0) ; /* traps put_ptr > put_end */
+ vio_fifo_add_lump(vff) ; /* traps put_ptr > put_end */
if (request > 0)
--request ;
@@ -1005,107 +721,132 @@ vio_fifo_read_nb(vio_fifo vff, int fd, uint request)
} while (request > 0) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+
return total ;
} ;
/*==============================================================================
- * Copy operations -- from one fifo to another.
+ * Copy operations -- from one FIFO to another.
*/
/*------------------------------------------------------------------------------
- * Copy src fifo (everything from get_ptr to end_mark or put_ptr) to dst fifo.
+ * Copy src FIFO (everything from get_ptr to end mark or put_ptr) to dst FIFO.
*
- * Create a dst fifo if there isn't one.
+ * Create a dst FIFO if there isn't one. There must be a src FIFO.
*
- * Appends to the dst fifo.
+ * Appends to the dst FIFO.
*
- * Does not change the src fifo in any way.
+ * Does not change the src FIFO in any way.
*/
extern vio_fifo
vio_fifo_copy(vio_fifo dst, vio_fifo src)
{
+ vio_fifo_lump src_lump ;
+ char* src_ptr ;
+
if (dst == NULL)
- dst = vio_fifo_init_new(dst, 0) ;
+ dst = vio_fifo_new(src->size) ;
- if ((src != 0) && (src->set))
- {
- vio_fifo_lump src_lump ;
- char* src_ptr ;
+ VIO_FIFO_DEBUG_VERIFY(src) ;
+ VIO_FIFO_DEBUG_VERIFY(dst) ;
- src_lump = src->get_lump ;
- src_ptr = src->get_ptr ;
+ src_lump = src->get_lump ;
+ src_ptr = src->get_ptr ;
- while (1)
- {
- char* src_end ;
+ while (1)
+ {
+ char* src_end ;
- if (src_lump != src->end_lump)
- src_end = src_lump->end ;
- else
- src_end = (src->end_mark) ? src->end_end : src->put_ptr ;
+ if (src_lump != src->end_lump)
+ src_end = src_lump->end ; /* end of not end_lump */
+ else
+ src_end = *src->p_end ; /* end of end_lump */
- vio_fifo_put_bytes(dst, src_ptr, src_end - src_ptr) ;
+ vio_fifo_put_bytes(dst, src_ptr, src_end - src_ptr) ;
- if (src_lump == src->end_lump)
- break ;
+ if (src_lump == src->end_lump)
+ break ;
- src_lump = ddl_next(src_lump, list) ;
- src_ptr = src_lump->data ;
- } ;
+ src_lump = ddl_next(src_lump, list) ;
+ src_ptr = src_lump->data ;
} ;
+ VIO_FIFO_DEBUG_VERIFY(dst) ;
+
return dst ;
} ;
/*------------------------------------------------------------------------------
- * Copy tail of src fifo (everything from end_mark to put_ptr) to dst fifo.
+ * Copy tail of src FIFO (everything from end mark to put_ptr) to dst FIFO.
*
- * Create a dst fifo if there isn't one.
+ * Create a dst FIFO if there isn't one. There must be a src FIFO.
*
- * Appends to the dst fifo.
+ * Appends to the dst FIFO.
*
- * Does not change the src fifo in any way.
+ * Does not change the src FIFO in any way.
*/
extern vio_fifo
vio_fifo_copy_tail(vio_fifo dst, vio_fifo src)
{
+ vio_fifo_lump src_lump ;
+ char* src_ptr ;
+ vio_fifo_lump tail ;
+
if (dst == NULL)
- dst = vio_fifo_init_new(dst, 0) ;
+ dst = vio_fifo_new(src->size) ;
- if ((src != 0) && (src->end_mark) && (src->set))
- {
- vio_fifo_lump src_lump ;
- char* src_ptr ;
- vio_fifo_lump tail ;
+ VIO_FIFO_DEBUG_VERIFY(src) ;
+ VIO_FIFO_DEBUG_VERIFY(dst) ;
- src_lump = src->end_lump ;
- src_ptr = src->end_end ;
- tail = ddl_tail(src->base) ;
+ if (!vio_fifo_have_end_mark(src))
+ return dst ;
- while (1)
- {
- char* src_end ;
+ src_lump = src->end_lump ;
+ src_ptr = src->end_ptr ;
+ tail = ddl_tail(src->base) ;
- if (src_lump != tail)
- src_end = src_lump->end ;
- else
- src_end = src->put_ptr ;
+ while (1)
+ {
+ char* src_end ;
- vio_fifo_put_bytes(dst, src_ptr, src_end - src_ptr) ;
+ if (src_lump != tail)
+ src_end = src_lump->end ;
+ else
+ src_end = src->put_ptr ;
- if (src_lump == tail)
- break ;
+ vio_fifo_put_bytes(dst, src_ptr, src_end - src_ptr) ;
- src_lump = ddl_next(src_lump, list) ;
- src_ptr = src_lump->data ;
- } ;
+ if (src_lump == tail)
+ break ;
+
+ src_lump = ddl_next(src_lump, list) ;
+ src_ptr = src_lump->data ;
} ;
+ VIO_FIFO_DEBUG_VERIFY(dst) ;
+
return dst ;
} ;
/*==============================================================================
* End Mark Operations.
+ *
+ * Set/Clear end mark is pretty straightforward:
+ *
+ * * if there was an end_ptr before and the put_ptr is ahead of it:
+ *
+ * this adds one or more bytes between the get_ptr and the (new) end.
+ *
+ * * if there was no end_ptr, or it is the same as the put_ptr:
+ *
+ * setting/clearing the end_ptr makes no difference, because whenever
+ * the get_ptr reaches the put_ptr, the pointers are reset if they can
+ * be -- so need not worry about that here.
+ *
+ * Set the p_end and p_get_end to the new reality.
+ *
+ * The put_ptr stays in its current lump, so no need to worry about put_end.
*/
/*------------------------------------------------------------------------------
@@ -1114,24 +855,20 @@ vio_fifo_copy_tail(vio_fifo dst, vio_fifo src)
* If there was an end_mark before, move it (forward) to the current put_ptr,
* which keeps everything in between in the FIFO.
*
- * Set the get_end to the new reality.
+ * If the put_ptr is at the end of the last lump, then the end_ptr will follow
+ * it if another lump is added to the FIFO.
+ *
+ * Set the p_end and p_get_end to the new reality.
*/
extern void
vio_fifo_set_end_mark(vio_fifo vff)
{
- if (vff->set)
- {
- vio_fifo_sync_get(vff) ; /* in case is currently empty */
-
- vff->end_lump = ddl_tail(vff->base) ;
- vff->end_end = vff->put_ptr ;
+ vff->p_end = &vff->end_ptr ;
- vff->get_end = (vff->get_lump == vff->end_lump) ? vff->end_end
- : vff->get_lump->end ;
- } ;
+ vff->end_ptr = vff->put_ptr ;
+ vff->end_lump = ddl_tail(vff->base) ;
- vff->as_one = false ; /* not as_one with end_mark */
- vff->end_mark = true ;
+ vio_fifo_set_get_end(vff) ; /* in case end_lump or p_end changed */
VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
@@ -1142,45 +879,36 @@ vio_fifo_set_end_mark(vio_fifo vff)
* If there was an end_mark before, move it (forward) to the current put_ptr,
* which keeps everything in between in the FIFO.
*
- * If there was no end_mark before, do nothing.
- *
- * Set the get_end to the new reality.
+ * If there was no end mark before, do nothing.
*/
extern void
vio_fifo_step_end_mark(vio_fifo vff)
{
- if (vff->end_mark)
- vio_fifo_set_end_mark(vff) ;
+ if (vio_fifo_have_end_mark(vff))
+ {
+ vff->end_ptr = vff->put_ptr ;
+ vff->end_lump = ddl_tail(vff->base) ;
+
+ vio_fifo_set_get_end(vff) ; /* in case end_lump changed */
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+ }
} ;
/*------------------------------------------------------------------------------
- * If there is an end_mark, clear it -- everything between end mark and
+ * If there is an end_ptr, clear it -- everything between end_ptr and the
* current put_ptr is kept in the FIFO.
*
- * Set the get_end to the new reality.
+ * Set the p_end and p_get_end to the new reality.
*/
extern void
vio_fifo_clear_end_mark(vio_fifo vff)
{
- if (vff->end_mark)
- {
- vff->end_mark = false ;
+ vff->p_end = &vff->put_ptr ;
- if (vff->set)
- {
- vff->end_lump = ddl_tail(vff->base) ;
- vff->end_end = NULL ;
+ vff->end_lump = ddl_tail(vff->base) ;
- vff->as_one = (vff->get_lump == vff->end_lump) ;
- /* since now no end_mark */
- if (!vff->as_one)
- vff->get_end = vff->get_lump->end ;
- /* would have been end_end */
-
- vio_fifo_sync_get(vff) ; /* sets get_end if as_one and
- tidies up if now empty (!) */
- } ;
- } ;
+ vio_fifo_set_get_end(vff) ; /* in case end_lump or p_end changed */
VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
@@ -1191,38 +919,45 @@ vio_fifo_clear_end_mark(vio_fifo vff)
* If there is an end_mark, keep it if required.
*
* If there is no end mark, do nothing.
+ *
+ * If there is an end mark but it is the same as the put_ptr, then need do
+ * nothing at all.
+ *
+ * Note that: if there is an end mark, then p_end == &end_ptr, so if
+ * *p_end == put_ptr, then end_ptr == put_ptr ; if there is no end mark,
+ * then p_end == &put_ptr, so *p_end == put_ptr !!
*/
extern void
vio_fifo_back_to_end_mark(vio_fifo vff, bool keep)
{
- if (vff->end_mark)
+ if (*vff->p_end != vff->put_ptr) /* test for not-empty end mark */
{
- if (vff->set)
+ if (vio_fifo_debug)
+ assert(vio_fifo_have_end_mark(vff)) ;
+
+ if (vff->end_lump != ddl_tail(vff->base))
{
- vio_fifo_release_tail(vff, vff->end_lump) ;
-
- vff->put_ptr = vff->end_end ;
- vff->put_end = vio_fifo_true_lump_size(vff->end_lump) ;
-
- /* If retaining the existing end_mark, we retain the end_end and
- * the current as_one (false).
- *
- * Otherwise...
- */
- if (!keep)
- {
- vff->end_mark = false ;
- vff->end_end = NULL ;
- vff->as_one = (vff->get_lump == vff->end_lump) ;
- } ;
-
- vio_fifo_sync_get(vff) ; /* in case now empty */
-
- VIO_FIFO_DEBUG_VERIFY(vff) ;
- }
+ vio_fifo_lump lump ;
+ do
+ vio_fifo_release_lump(vff, ddl_crop(&lump, vff->base, list)) ;
+ while (vff->end_lump != ddl_tail(vff->base)) ;
+
+ vff->put_end = vff->end_lump->end ;
+ } ;
+
+ if (*vff->p_start == vff->end_ptr)
+ vio_fifo_reset_ptrs(vff) ;
else
- vff->end_mark = keep ;
+ vff->put_ptr = vff->end_ptr ;
} ;
+
+ if (!keep)
+ {
+ vff->p_end = &vff->put_ptr ;
+ vio_fifo_set_get_end(vff) ; /* in case get_lump == end_lump */
+ } ;
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
/*==============================================================================
@@ -1230,121 +965,40 @@ vio_fifo_back_to_end_mark(vio_fifo vff, bool keep)
*/
/*------------------------------------------------------------------------------
- * Get upto 'n' bytes.
+ * Get upto 'n' bytes -- steps past the bytes fetched.
*
* Returns: number of bytes got -- may be zero.
*/
-extern size_t
-vio_fifo_get_bytes(vio_fifo vff, void* dst, size_t n)
+extern ulen
+vio_fifo_get_bytes(vio_fifo vff, void* dst, ulen n)
{
- size_t have ;
- void* dst_in ;
+ void* dst_start ;
VIO_FIFO_DEBUG_VERIFY(vff) ;
- dst_in = dst ;
- while (vio_fifo_sync_get(vff) && (n > 0))
+ dst_start = dst ;
+ while (n > 0)
{
- have = vff->get_end - vff->get_ptr ;
+ ulen take ;
- if (have > n)
- have = n ;
+ take = *vff->p_get_end - vff->get_ptr ;
- memcpy(dst, vff->get_ptr, have) ;
- vff->get_ptr += have ;
- dst = (char*)dst + have ;
-
- n -= have ;
- } ;
+ if (take > n)
+ take = n ;
+ else if (take == 0)
+ break ;
- VIO_FIFO_DEBUG_VERIFY(vff) ;
+ memcpy(dst, vff->get_ptr, take) ;
+ dst = (char*)dst + take ;
- return (char*)dst - (char*)dst_in ;
-} ;
+ n -= take ;
-/*------------------------------------------------------------------------------
- * Get byte -- the long winded way.
- *
- * See the inline vio_fifo_get_byte().
- *
- * The version is used when the get_ptr is at or just before the end of the
- * current lump. Looks after all the necessary pointer updates associated with
- * hitting end of lump, or hitting end of FIFO.
- *
- * Returns: 0x00..0xFF -- byte value (as an int)
- * -1 => FIFO is empty.
- */
-Private int
-vio_fifo_get_next_byte(vio_fifo vff)
-{
- if (vio_fifo_sync_get(vff))
- return (uchar)*vff->get_ptr++ ;
-
- return -1 ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Get pointer to as many bytes as are available in the current lump (or next
- * lump if nothing available in the current).
- *
- * Returns: address of next byte to get, *p_have = number of bytes available
- * or: NULL => FIFO is empty, *p_have = 0
- *
- * If the FIFO is not empty and not at the end_mark, will return pointer to at
- * least one byte. There may be more bytes to get in further lumps.
- */
-extern void*
-vio_fifo_get(vio_fifo vff, size_t* p_have)
-{
- if (vio_fifo_sync_get(vff))
- {
- *p_have = (vff->get_end - vff->get_ptr) ;
- return vff->get_ptr ;
+ vio_fifo_step(vff, take) ;
} ;
- *p_have = 0 ;
- return NULL ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Step FIFO past bytes used.
- *
- * Can be called after a vio_fifo_get() or vio_fifo_step_get().
- *
- * NB: the "step" argument MUST not exceed the "have" previously returned.
- */
-extern void
-vio_fifo_step(vio_fifo vff, size_t step)
-{
- vff->get_ptr += step ;
- vio_fifo_sync_get(vff) ; /* ensure up to date with that */
-
VIO_FIFO_DEBUG_VERIFY(vff) ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Step FIFO past bytes used, the get pointer to as many bytes as are available
- * in the current lump (or next lump if nothing available in the current).
- *
- * Same as vio_fifo_step() followed by vio_fifo_get().
- *
- * Can be called after a vio_fifo_get() or vio_fifo_step_get().
- *
- * NB: the "step" argument MUST not exceed the "have" previously returned.
- */
-extern void*
-vio_fifo_step_get(vio_fifo vff, size_t* p_have, size_t step)
-{
- vff->get_ptr += step ;
- if (vio_fifo_sync_get(vff))
- {
- *p_have = (vff->get_end - vff->get_ptr) ;
- return vff->get_ptr ;
- } ;
-
- *p_have = 0 ;
- return NULL ;
+ return (char*)dst - (char*)dst_start ;
} ;
/*------------------------------------------------------------------------------
@@ -1363,17 +1017,22 @@ vio_fifo_step_get(vio_fifo vff, size_t* p_have, size_t step)
extern int
vio_fifo_write_nb(vio_fifo vff, int fd, bool all)
{
- char* src ;
- size_t have ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
- while ((src = vio_fifo_get(vff, &have)) != NULL)
+ while (1)
{
- int done ;
+ ulen have ;
+ int done ;
if ((vff->get_lump == vff->end_lump) && !all)
break ; /* don't write last lump */
- done = write_nb(fd, src, have) ;
+ have = vio_fifo_get(vff) ;
+
+ if (have == 0)
+ break ;
+
+ done = write_nb(fd, vio_fifo_get_ptr(vff), have) ;
if (done < 0)
return -1 ; /* failed */
@@ -1384,6 +1043,8 @@ vio_fifo_write_nb(vio_fifo vff, int fd, bool all)
return 1 ; /* blocked */
} ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+
return 0 ; /* all gone */
} ;
@@ -1401,14 +1062,18 @@ vio_fifo_write_nb(vio_fifo vff, int fd, bool all)
extern int
vio_fifo_fwrite(vio_fifo vff, FILE* file)
{
- char* src ;
- size_t have ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
- while ((src = vio_fifo_get(vff, &have)) != NULL)
+ while (1)
{
- size_t done ;
+ int done ;
+ ulen have ;
+
+ have = vio_fifo_get(vff) ;
+ if (have == 0)
+ break ;
- done = fwrite(src, have, 1, file) ;
+ done = fwrite(vio_fifo_get_ptr(vff), have, 1, file) ;
if (done < 1)
return -1 ; /* failed */
@@ -1416,82 +1081,80 @@ vio_fifo_fwrite(vio_fifo vff, FILE* file)
vio_fifo_step(vff, have) ;
} ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+
return 0 ; /* all gone */
} ;
/*------------------------------------------------------------------------------
- * Skip get_ptr to the current end -- which may be the current end_mark.
+ * Skip get_ptr to the current end -- which may be the current end mark.
*
- * Does not clear any hold_mark or end_mark.
+ * Does not clear any hold_ptr or end_ptr.
*/
extern void
vio_fifo_skip_to_end(vio_fifo vff)
{
- vio_fifo_sync_get(vff) ; /* ensure all straight */
-
- /* Setting the get_ptr to the start of the end_lump does the bulk
- * of the work -- then just skip to the get_end which that sets.
+ /* Advance directly to the current end and then synchronise get_ptr
*/
- vio_fifo_set_get_ptr(vff, vff->end_lump->data, vff->end_lump) ;
- vff->get_ptr = vff->get_end ;
+ vff->get_lump = vff->end_lump ;
+ vff->get_ptr = *vff->p_end ;
+ vff->p_get_end = vff->p_end ;
- vio_fifo_sync_get(vff) ; /* crunch */
+ vio_fifo_sync_get(vff) ;
} ;
/*==============================================================================
* Hold Mark Operations.
+ *
+ * Set or clear hold_ptr.
+ *
+ * The get_ptr is unambiguous -- so the hold_ptr is, because it is only ever
+ * set equal to the get_ptr !
+ *
+ * The put_ptr stays in its current lump, so no need to worry about put_end.
*/
/*------------------------------------------------------------------------------
- * If there is a hold_mark, clear it -- discard all contents up to the
- * current get_ptr.
+ * Set hold mark -- clearing existing one, if any.
*
- * Set hold_mark at the current get_ptr.
+ * Discard all contents up to the current get_ptr (easy if no hold mark), then
+ * set hold mark at get_ptr.
*/
extern void
vio_fifo_set_hold_mark(vio_fifo vff)
{
- if (vff->set)
- {
- if (vff->hold_mark)
- vio_fifo_clear_hold_mark(vff) ; /* clear existing mark & sync */
- else
- vio_fifo_sync_get(vff) ; /* ensure all straight */
+ vio_fifo_release_upto(vff, vff->get_lump) ;
- vff->hold_ptr = vff->get_ptr ;
- } ;
+ if (vff->get_ptr == vff->put_ptr)
+ vio_fifo_reset_ptrs(vff) ;
+ else
+ vff->hold_ptr = vff->get_ptr ;
- vff->hold_mark = true ;
+ vff->p_start = &vff->hold_ptr ;
VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
/*------------------------------------------------------------------------------
- * If there is a hold_mark, clear it -- discard all contents up to the
- * current get_ptr.
+ * Clear hold mark -- if any.
*
- * The get_ptr is synchronised.
+ * Discard all contents up to the current get_ptr (easy if no hold mark), then
+ * clear hold mark (no effect if not set).
+ *
+ * Note that clearing a hold_ptr in an empty FIFO resets all the pointers. To
+ * avoid that could test for an empty hold mark (*p_start == get_ptr), but the
+ * extra step in the majority case seems worse than the extra work in the
+ * minority one.
*/
extern void
vio_fifo_clear_hold_mark(vio_fifo vff)
{
- /* Make sure all is up to date, and in particular that the get_ptr
- * is not sitting at the end of a lump when there is a following lump.
- */
- vio_fifo_sync_get(vff) ;
+ vio_fifo_release_upto(vff, vff->get_lump) ;
- if ((vff->hold_mark) && (vff->set))
- {
- /* Release everything upto but not including the current get_lump.
- *
- * This has no effect on the get_ptr etc. so they remain straight.
- */
- vio_fifo_release_head(vff, vff->get_lump) ;
+ if (vff->get_ptr == vff->put_ptr)
+ vio_fifo_reset_ptrs(vff) ;
- vff->hold_ptr = NULL ;
- } ;
-
- vff->hold_mark = false ;
+ vff->p_start = &vff->get_ptr ;
VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
@@ -1501,86 +1164,19 @@ vio_fifo_clear_hold_mark(vio_fifo vff)
* set or clear.
*
* If there is no hold mark, set one at the current position, if required.
- */
-extern void
-vio_fifo_back_to_hold_mark(vio_fifo vff, bool mark)
-{
- if (vff->hold_mark)
- {
- if (vff->set)
- {
- vio_fifo_set_get_ptr(vff, vff->hold_ptr, ddl_head(vff->base)) ;
- /* Set back to hold position */
-
- vff->end_mark = mark ; /* new state */
- if (!mark)
- vff->hold_ptr = NULL ; /* clear if required */
-
- vio_fifo_sync_get(vff) ; /* to be absolutely sure ! */
- } ;
-
- VIO_FIFO_DEBUG_VERIFY(vff) ;
- }
- else if (mark)
- vio_fifo_set_hold_mark(vff) ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Set the get_ptr to the hold_mark plus the given offset.
- *
- * If the offset is zero, and there was no hold mark, set one at the current
- * get_ptr.
*
- * If the offset is not zero, it is a mistake to do this if there is no
- * hold_mark, or if the offset would take the get_ptr beyond the end_mark
- * (if any) or the put_ptr.
+ * Setting the get_ptr back to the hold_ptr sets it to an unambiguous
+ * position. If the get_ptr == hold_ptr then if the FIFO is empty, the
+ * pointers will have been reset.
*/
extern void
-vio_fifo_set_get_wrt_hold(vio_fifo vff, size_t hold_offset)
+vio_fifo_back_to_hold_mark(vio_fifo vff, on_off_b set)
{
- if (hold_offset == 0)
- {
- /* Offset of zero can be set under all conditions */
- vio_fifo_back_to_hold_mark(vff, true) ;
- }
- else
- {
- vio_fifo_lump lump ;
- char* ptr ;
+ if (vio_fifo_have_hold_mark(vff))
+ vio_fifo_set_get_ptr(vff, ddl_head(vff->base), vff->hold_ptr) ;
- /* There must be a hold_mark and must have something held */
- assert(vff->hold_mark && vff->set) ;
+ vff->p_start = (set) ? &vff->hold_ptr : &vff->get_ptr ;
- lump = ddl_head(vff->base) ;
- ptr = vff->hold_ptr ;
-
- while (1)
- {
- size_t have ;
-
- if (lump == vff->end_lump)
- have = (vff->end_mark ? vff->end_end : vff->put_ptr) - ptr ;
- else
- have = lump->end - ptr ;
-
- if (have <= hold_offset)
- break ;
-
- hold_offset -= have ;
-
- assert(lump != vff->end_lump) ;
-
- lump = ddl_next(lump, list) ;
- ptr = lump->data ;
- } ;
-
- /* Note that may be about to set the get_ptr to the end of the
- * current lump, which will be correct if that is the end of the
- * fifo, but in any case is dealt with by vio_fifo_sync_get().
- */
- vio_fifo_set_get_ptr(vff, ptr + hold_offset, lump) ;
- vio_fifo_sync_get(vff) ;
- } ;
VIO_FIFO_DEBUG_VERIFY(vff) ;
} ;
@@ -1594,45 +1190,32 @@ vio_fifo_verify(vio_fifo vff)
vio_fifo_lump head ;
vio_fifo_lump lump ;
vio_fifo_lump tail ;
+ bool own_seen ;
head = ddl_head(vff->base) ;
tail = ddl_tail(vff->base) ;
- /* If nothing allocated, should all be NULL & !vff->set */
- /* If something allocated, tail must not be NULL */
+ /* FIFO always has at least one lump. */
if (head == NULL)
- {
- if ( (tail != NULL)
- || (vff->set)
- || (vff->as_one)
- || (vff->hold_ptr != NULL)
- || (vff->get_lump != NULL)
- || (vff->get_ptr != NULL)
- || (vff->get_end != NULL)
- || (vff->end_lump != NULL)
- || (vff->end_end != NULL)
- || (vff->put_ptr != NULL)
- || (vff->put_end != NULL) )
- zabort("nothing allocated, but not all NULL") ;
- return ;
- }
- else
- {
- if (tail == NULL)
- zabort("head not NULL, but tail is") ;
- } ;
-
- /* Must now be set ! */
- if (!vff->set)
- zabort("head not NULL, but set is false") ;
+ zabort("head is NULL") ;
+ if (tail == NULL)
+ zabort("tail is NULL") ;
/* Make sure that the lump pointers all work
*
* When finished, know that head <= get_lump <= end_lump <= tail.
*/
+ own_seen = false ;
+
lump = head ;
- while (lump != vff->get_lump)
+ while (1)
{
+ if (lump == vff->own_lump)
+ own_seen = true ;
+
+ if (lump == vff->get_lump)
+ break ;
+
lump = ddl_next(lump, list) ;
if (lump == NULL)
zabort("ran out of lumps looking for get_lump") ;
@@ -1641,15 +1224,53 @@ vio_fifo_verify(vio_fifo vff)
while (lump != vff->end_lump)
{
lump = ddl_next(lump, list) ;
+
if (lump == NULL)
zabort("ran out of lumps looking for end_lump") ;
+
+ if (lump == vff->own_lump)
+ own_seen = true ;
} ;
while (lump != tail)
{
lump = ddl_next(lump, list) ;
+
if (lump == NULL)
zabort("ran out of lumps looking for tail") ;
+
+ if (lump == vff->own_lump)
+ own_seen = true ;
+ } ;
+
+ if (vff->spare == vff->own_lump)
+ {
+ if (own_seen)
+ zabort("own seen in FIFO, but is also spare") ;
+ }
+ else
+ {
+ if (!own_seen)
+ zabort("not found own lump in the FIFO") ;
+ } ;
+
+ /* Check that the p_start, p_get_end and p_end are valid
+ */
+ if ((vff->p_start != &vff->hold_ptr) && (vff->p_start != &vff->get_ptr))
+ zabort("p_start is neither &get_ptr nor &hold_ptr") ;
+
+ if ((vff->p_end != &vff->end_ptr) && (vff->p_end != &vff->put_ptr))
+ zabort("p_end is neither &put_ptr nor &end_ptr") ;
+
+ if (vff->get_lump == vff->end_lump)
+ {
+ if (vff->p_get_end != vff->p_end)
+ zabort("p_get_end not equal to p_end and is in end_lump") ;
+ }
+ else
+ {
+ if (vff->p_get_end != &vff->get_lump->end)
+ zabort("p_get_end not equal to get_lump->end and is not in end_lump") ;
} ;
/* Check that all the pointers are within respective lumps
@@ -1663,45 +1284,41 @@ vio_fifo_verify(vio_fifo vff)
* - that all pointers are within their respective lumps
* - all ptr are <= their respective ends
* - if hold_mark: hold_ptr <= get_ptr or head != get_lump
- * - if end_mark: end_end <= put_ptr or tail != end_lump
+ * - if end_mark: end_ptr <= put_ptr or tail != end_lump
*/
- if (vff->hold_mark)
+ if (vio_fifo_have_hold_mark(vff))
{
if ( (head->data > vff->hold_ptr)
|| (vff->hold_ptr > head->end) )
- zabort("hold pointer outside the head lump") ;
+ zabort("hold_ptr outside the head lump") ;
if ((vff->get_lump == head) && (vff->hold_ptr > vff->get_ptr))
- zabort("hold pointer greater than get pointer") ;
+ zabort("hold_ptr greater than get_ptr") ;
}
else
{
- if (vff->hold_ptr != NULL)
- zabort("no hold_mark, but hold pointer not NULL") ;
if (vff->get_lump != head)
- zabort("no hold_mark, but get_lump is not head") ;
+ zabort("no hold_ptr, but get_lump is not head") ;
} ;
if ( (vff->get_lump->data > vff->get_ptr)
- || (vff->get_ptr > vff->get_end)
- || (vff->get_end > vff->get_lump->end))
+ || (vff->get_ptr > *vff->p_get_end)
+ || (*vff->p_get_end > vff->get_lump->end))
zabort("get pointers outside the get lump") ;
- if (vff->end_mark)
+ if (vio_fifo_have_end_mark(vff))
{
- if ( (vff->end_lump->data > vff->end_end)
- || (vff->end_end > vff->end_lump->end) )
+ if ( (vff->end_lump->data > vff->end_ptr)
+ || (vff->end_ptr > vff->end_lump->end) )
zabort("end pointer outside the end lump") ;
- if ((vff->end_lump == tail) && (vff->end_end > vff->put_ptr))
+ if ((vff->end_lump == tail) && (vff->end_ptr > vff->put_ptr))
zabort("end pointer greater than put pointer") ;
}
else
{
- if (vff->end_end != NULL)
- zabort("no end_mark, but end end not NULL") ;
if (vff->end_lump != tail)
- zabort("no end_mark, but end_lump is not tail") ;
+ zabort("no end_ptr, but end_lump is not tail") ;
} ;
if ( (tail->data > vff->put_ptr)
@@ -1709,27 +1326,35 @@ vio_fifo_verify(vio_fifo vff)
|| (vff->put_end != tail->end) )
zabort("put pointers outside the tail lump") ;
- /* The as_one state & get_end
+ /* Check that if get_ptr == p_get_end, that it is empty, or there is some
+ * not-empty hold or end mark.
+ *
+ * The point is to trap any failure to reset pointers or advance the get_ptr
+ * when it hits *p_get_end.
*/
- if (vff->get_lump != vff->end_lump)
- {
- if (vff->as_one)
- zabort("get_lump != end_lump, but as_one true") ;
- if (vff->get_end != vff->get_lump->end)
- zabort("get_lump != end_lump, but get_end != get_lump->end") ;
- }
- else if (vff->end_mark)
+ if (vff->get_ptr == *vff->p_get_end)
{
- if (vff->as_one)
- zabort("end_mark true, but as_one also true") ;
- if (vff->get_end != vff->end_end)
- zabort("get_lump == end_lump and end_mark, but get_end != end_end") ;
- }
- else
+ if (*vff->p_start != vff->put_ptr)
+ {
+ /* Not empty -- so must have a hold and/or end */
+ if (!(vio_fifo_have_hold_mark(vff) || vio_fifo_have_end_mark(vff)))
+ zabort("get_ptr is at get_end, is not empty by no marks set") ;
+ } ;
+ } ;
+
+ /* Check that if is empty, the pointers are reset.
+ */
+ if (*vff->p_start == vff->put_ptr)
{
- if (!vff->as_one)
- zabort("get_lump == end_lump and !end_mark, but as_one not true") ;
- if (vff->get_end > vff->put_ptr)
- zabort("is as_one, but get_end > put_ptr") ;
+ if ( (tail != head)
+ || (vff->get_lump != head)
+ || (vff->end_lump != head)
+ || (vff->get_ptr != head->data)
+ || (vff->put_ptr != head->data)
+ || (vff->put_end != head->end)
+ || !( (vff->hold_ptr == NULL) || (vff->hold_ptr == head->data) )
+ || !( (vff->end_ptr == NULL) || (vff->end_ptr == head->data) )
+ )
+ zabort("pointers not valid for empty fifo") ;
} ;
} ;
diff --git a/lib/vio_fifo.h b/lib/vio_fifo.h
index 97575f51..03437ae4 100644
--- a/lib/vio_fifo.h
+++ b/lib/vio_fifo.h
@@ -67,38 +67,47 @@ enum { vio_fifo_debug = VIO_FIFO_DEBUG } ;
/*==============================================================================
* Data Structures
+ *
+ * Note that the main fifo structure contains the first "lump", so the fifo
+ * always contains at least one.
*/
typedef struct vio_fifo_lump vio_fifo_lump_t ;
typedef struct vio_fifo_lump* vio_fifo_lump ;
-struct vio_fifo
+struct vio_fifo_lump
{
- struct dl_base_pair(vio_fifo_lump) base ;
+ struct dl_list_pair(vio_fifo_lump) list ;
- bool set ; /* have at least one lump */
+ char* end ; /* end of this particular lump */
+ char data[] ;
+} ;
- bool as_one ; /* get_lump == tail && !end_mark
- => get_end may not be up to date */
+struct vio_fifo
+{
+ struct dl_base_pair(vio_fifo_lump) base ;
- bool hold_mark ; /* hold stuff while getting */
- bool end_mark ; /* do not get beyond end */
+ char** p_start ; /* -> hold_ptr/get_ptr */
char* hold_ptr ; /* implicitly in the head lump */
- /* used only if "hold_mark" */
+ /* NULL <=> no hold_ptr */
- vio_fifo_lump get_lump ; /* head lump unless "hold_mark" */
+ vio_fifo_lump get_lump ; /* head lump unless "hold_ptr" */
char* get_ptr ;
- char* get_end ;
- vio_fifo_lump end_lump ; /* tail lump unless "end_mark" */
- char* end_end ; /* used only if "end_mark" */
+ char** p_get_end ; /* -> lump->end/end_ptr/put_ptr */
+ char** p_end ; /* -> end_ptr/put_ptr */
+
+ vio_fifo_lump end_lump ; /* tail lump unless "end_ptr" */
+ char* end_ptr ; /* NULL <=> no end_ptr */
char* put_ptr ; /* implicitly in the tail lump */
char* put_end ;
- size_t size ;
+ ulen size ; /* set when initialised */
+
+ vio_fifo_lump spare ; /* may be "own_lump" */
- vio_fifo_lump spare ;
+ vio_fifo_lump_t own_lump[] ; /* embedded lump */
} ;
typedef struct vio_fifo vio_fifo_t[1] ; /* embedded */
@@ -115,45 +124,34 @@ enum
#define VIO_FIFO_INIT_EMPTY { 0 }
-struct vio_fifo_lump
-{
- struct dl_list_pair(vio_fifo_lump) list ;
-
- char* end ; /* end of this particular lump */
- size_t size ; /* size of lump when allocated */
- char data[] ;
-} ;
-
/*==============================================================================
* Functions
*/
-
-extern vio_fifo vio_fifo_init_new(vio_fifo vff, size_t size) ;
-extern vio_fifo vio_fifo_reset(vio_fifo vff, free_keep_b free_structure) ;
+extern vio_fifo vio_fifo_new(ulen size) ;
+extern vio_fifo vio_fifo_free(vio_fifo vff) ;
extern void vio_fifo_clear(vio_fifo vff, bool clear_marks) ;
Inline bool vio_fifo_empty(vio_fifo vff) ;
Inline bool vio_fifo_tail_empty(vio_fifo vff) ;
-extern size_t vio_fifo_room(vio_fifo vff) ;
-extern void vio_fifo_put_bytes(vio_fifo vff, const char* src, size_t n) ;
+extern void vio_fifo_put_bytes(vio_fifo vff, const char* src, ulen n) ;
Inline void vio_fifo_put_byte(vio_fifo vff, char b) ;
extern int vio_fifo_printf(vio_fifo vff, const char* format, ...)
PRINTF_ATTRIBUTE(2, 3) ;
extern int vio_fifo_vprintf(vio_fifo vff, const char *format, va_list args) ;
-extern int vio_fifo_read_nb(vio_fifo vff, int fd, uint request) ;
+extern int vio_fifo_read_nb(vio_fifo vff, int fd, ulen request) ;
-extern size_t vio_fifo_get_bytes(vio_fifo vff, void* dst, size_t n) ;
+extern ulen vio_fifo_get_bytes(vio_fifo vff, void* dst, ulen n) ;
Inline int vio_fifo_get_byte(vio_fifo vff) ;
-extern void* vio_fifo_get(vio_fifo vff, size_t* have) ;
-extern void vio_fifo_step(vio_fifo vff, size_t step) ;
-extern void* vio_fifo_step_get(vio_fifo vff, size_t* p_have, size_t step) ;
+Inline ulen vio_fifo_get(vio_fifo vff) ;
+Inline void* vio_fifo_get_ptr(vio_fifo vff) ;
+Inline void vio_fifo_step(vio_fifo vff, ulen step) ;
+Inline ulen vio_fifo_step_get(vio_fifo vff, ulen step) ;
extern vio_fifo vio_fifo_copy(vio_fifo dst, vio_fifo src) ;
extern vio_fifo vio_fifo_copy_tail(vio_fifo dst, vio_fifo src) ;
-Inline bool vio_fifo_full_lump(vio_fifo vff) ;
extern int vio_fifo_write_nb(vio_fifo vff, int fd, bool all) ;
extern int vio_fifo_fwrite(vio_fifo vff, FILE* file) ;
@@ -164,8 +162,7 @@ extern void vio_fifo_clear_end_mark(vio_fifo vff) ;
extern void vio_fifo_back_to_end_mark(vio_fifo vff, bool keep) ;
extern void vio_fifo_set_hold_mark(vio_fifo vff) ;
extern void vio_fifo_clear_hold_mark(vio_fifo vff) ;
-extern void vio_fifo_back_to_hold_mark(vio_fifo vff, bool keep) ;
-extern void vio_fifo_set_get_wrt_hold(vio_fifo vff, size_t hold_offset) ;
+extern void vio_fifo_back_to_hold_mark(vio_fifo vff, on_off_b on) ;
/*==============================================================================
* Debug -- verification function
@@ -179,47 +176,30 @@ Private void vio_fifo_verify(vio_fifo vff) ;
* Inline Functions
*/
-Private void vio_fifo_lump_new(vio_fifo vff, size_t size) ;
-Private int vio_fifo_get_next_byte(vio_fifo vff) ;
-Private bool vio_fifo_do_empty(vio_fifo vff) ;
+Private void vio_fifo_add_lump(vio_fifo vff) ;
+Private void vio_fifo_sync_get(vio_fifo vff) ;
/*------------------------------------------------------------------------------
- * Returns true <=> FIFO is empty -- at least: get_ptr == end_end (if any)
+ * Returns true <=> FIFO is empty -- at least: get_ptr == end_ptr (if any)
* or: get_ptr == put_ptr.
*/
Inline bool
vio_fifo_empty(vio_fifo vff)
{
- /* if vff is NULL, treat as empty !
- * if !set, then all pointers should be NULL (so get_ptr == put_ptr)
- * if !end_mark, then vff->end_end will be NULL (so get_ptr != end_end,
- * unless !set)
- * Is definitely empty if any of the following is true.
- */
- if ((vff == NULL) || (vff->get_ptr == vff->put_ptr)
- || (vff->get_ptr == vff->end_end))
- return true ;
-
- /* If get_ptr < get_end is NOT empty */
- if (vff->get_ptr < vff->get_end)
- return false ;
-
- /* See if can advance get_ptr, and if so whether is then empty. */
- return vio_fifo_do_empty(vff) ;
+ return (vff == NULL) || (vff->get_ptr == *vff->p_end) ;
} ;
/*------------------------------------------------------------------------------
- * Returns true <=> FIFO is empty beyond end_end (if any).
+ * Returns true <=> FIFO is empty beyond end_ptr (if any).
*/
Inline bool
vio_fifo_tail_empty(vio_fifo vff)
{
/* if vff is NULL, treat as empty !
- * if !set, then all pointers should be NULL (so end_end == put_ptr)
- * if !end_mark, then tail is empty !
- * else tail is empty iff end_end == put_ptr.
+ * if end_ptr is NULL, then tail is empty !
+ * else tail is empty iff end_ptr == put_ptr.
*/
- return (vff == NULL) || !vff->end_mark || (vff->end_end == vff->put_ptr) ;
+ return (vff == NULL) || (vff->put_ptr == *vff->p_end) ;
} ;
/*------------------------------------------------------------------------------
@@ -229,7 +209,7 @@ Inline void
vio_fifo_put_byte(vio_fifo vff, char b)
{
if (vff->put_ptr >= vff->put_end)
- vio_fifo_lump_new(vff, 0) ; /* traps put_ptr > put_end */
+ vio_fifo_add_lump(vff) ; /* traps put_ptr > put_end */
VIO_FIFO_DEBUG_VERIFY(vff) ;
@@ -245,25 +225,71 @@ vio_fifo_put_byte(vio_fifo vff, char b)
Inline int
vio_fifo_get_byte(vio_fifo vff)
{
- if (vff->get_ptr < vff->get_end)
- return (uchar)*vff->get_ptr++ ;
+ if (vff->get_ptr < *vff->p_get_end)
+ {
+ int ch ;
+ ch = (uchar)*vff->get_ptr ;
- return vio_fifo_get_next_byte(vff) ;
+ vio_fifo_step(vff, 1) ;
+
+ return ch ;
+ }
+
+ return -1 ;
} ;
/*------------------------------------------------------------------------------
- * See if have at least one full lump.
+ * Get count of bytes available in the current lump.
*
- * This may be used with vio_fifo_write_nb(..., false) to use FIFO as a sort of
- * double buffer.
+ * There will always be at least 1 byte available in the current lump, unless
+ * the FIFO is empty, or at the end mark.
*
- * Returns: true <=> there is at least one full lump in the FIFO
- * (excluding the last lump if it happens to be full)
+ * Returns: address of bytes to get
*/
-Inline bool
-vio_fifo_full_lump(vio_fifo vff)
+Inline ulen
+vio_fifo_get(vio_fifo vff)
+{
+ return *vff->p_get_end - vff->get_ptr ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get pointer to bytes in the current lump.
+ *
+ * NB: to be called only after vio_fifo_get(), or vio_fifo_steo_get() have
+ * returned a non-zero value.
+ */
+Inline void*
+vio_fifo_get_ptr(vio_fifo vff)
+{
+ return vff->get_ptr ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Step FIFO past bytes used.
+ *
+ * Can be called after a vio_fifo_get() or vio_fifo_step_get().
+ *
+ * NB: the "step" argument MUST not exceed the "have" previously returned.
+ */
+Inline void
+vio_fifo_step(vio_fifo vff, ulen step)
+{
+ vff->get_ptr += step ;
+
+ if (vff->get_ptr >= *vff->p_get_end)
+ vio_fifo_sync_get(vff) ;
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * vio_fifo_step() forllowed by vio_fifo_get() !
+ */
+Inline ulen
+vio_fifo_step_get(vio_fifo vff, ulen step)
{
- return (ddl_head(vff->base) != ddl_tail(vff->base)) ;
+ vio_fifo_step(vff, step) ;
+ return vio_fifo_get(vff) ;
} ;
#endif /* _ZEBRA_VIO_FIFO_H */
diff --git a/lib/vio_lines.c b/lib/vio_lines.c
index 031f4539..2a6a89d1 100644
--- a/lib/vio_lines.c
+++ b/lib/vio_lines.c
@@ -21,7 +21,6 @@
#include "misc.h"
#include "memory.h"
-#include "zassert.h"
#include "vio_lines.h"
#include "qiovec.h"
diff --git a/lib/vty.c b/lib/vty.c
index 9020cb61..173b59e1 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -21,7 +21,6 @@
* 02111-1307, USA.
*/
-#include "zconfig.h"
#include "misc.h"
#include "lib/version.h"
diff --git a/lib/vty_cli.c b/lib/vty_cli.c
index 3b82a112..311d950c 100644
--- a/lib/vty_cli.c
+++ b/lib/vty_cli.c
@@ -155,7 +155,7 @@ uty_cli_new(vio_vf vf)
cli->cls = qs_new(120) ;
cli->clx = qs_new(120) ;
- cli->cbuf = vio_fifo_init_new(NULL, 1000) ;
+ cli->cbuf = vio_fifo_new(1000) ;
cli->olc = vio_lc_new(0 , 0, telnet_newline) ;
@@ -258,12 +258,12 @@ uty_cli_close(vty_cli cli, bool final)
/* If final, free the CLI object. */
if (final)
{
- cli->prompt_for_node = qs_reset(cli->prompt_for_node, free_it) ;
- cli->cl = qs_reset(cli->cl, free_it) ;
- cli->cls = qs_reset(cli->cls, free_it) ;
+ cli->prompt_for_node = qs_free(cli->prompt_for_node) ;
+ cli->cl = qs_free(cli->cl) ;
+ cli->cls = qs_free(cli->cls) ;
- cli->cbuf = vio_fifo_reset(cli->cbuf, free_it) ;
- cli->olc = vio_lc_reset(cli->olc, free_it) ;
+ cli->cbuf = vio_fifo_free(cli->cbuf) ;
+ cli->olc = vio_lc_free(cli->olc) ;
XFREE(MTYPE_VTY_CLI, cli) ; /* sets cli = NULL */
} ;
diff --git a/lib/vty_command.c b/lib/vty_command.c
index 0ce31fdf..9aebc50f 100644
--- a/lib/vty_command.c
+++ b/lib/vty_command.c
@@ -1026,7 +1026,7 @@ uty_cmd_hiatus(vty_io vio, cmd_return_code_t ret)
if (vio->ebuf != NULL)
{
vio_fifo_copy(vio->obuf, vio->ebuf) ;
- vio->ebuf = vio_fifo_reset(vio->ebuf, free_it) ;
+ vio->ebuf = vio_fifo_free(vio->ebuf) ;
ret = uty_cmd_out_push(vio->vout, vio->err_hard) ;
@@ -1351,9 +1351,9 @@ vty_cmd_success(vty vty)
if (!vio_fifo_tail_empty(vio->obuf))
{
if (!vty->exec->out_suppress)
- ret = uty_cmd_out_push(vio->vout, false) ; /* not final */
+ ret = uty_cmd_out_push(vio->vout, false) ; /* not final */
else
- uty_out_clear(vio) ;
+ vio_fifo_back_to_end_mark(vio->obuf, true) ; /* keep end mark */
} ;
} ;
@@ -1526,7 +1526,7 @@ uty_cmd_failed(vty_io vio, cmd_return_code_t ret)
if (vio->ebuf != NULL)
vio_fifo_clear(vio->ebuf, true) ;
else
- vio->ebuf = vio_fifo_init_new(NULL, 1000) ;
+ vio->ebuf = vio_fifo_new(1000) ;
indent = uty_show_error_context(vio->ebuf, vio->vin) ;
diff --git a/lib/vty_io.c b/lib/vty_io.c
index dadfd091..96df3850 100644
--- a/lib/vty_io.c
+++ b/lib/vty_io.c
@@ -20,6 +20,7 @@
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
+#include "misc.h"
#include "vty.h"
#include "vty_io.h"
@@ -323,8 +324,8 @@ uty_vin_push(vty_io vio, vio_vf vf, vio_in_type_t type,
if (ibuf_size != 0)
{
- vf->ibuf = vio_fifo_init_new(NULL, ibuf_size) ;
- vf->cl = qs_init_new(NULL, 120) ;
+ vf->ibuf = vio_fifo_new(ibuf_size) ;
+ vf->cl = qs_new(150) ;
vf->line_complete = true ;
vf->line_step = 1 ;
} ;
@@ -413,7 +414,7 @@ uty_vout_push(vty_io vio, vio_vf vf, vio_out_type_t type,
vio->vout_base = vf ;
} ;
- vf->obuf = vio_fifo_init_new(NULL, obuf_size) ;
+ vf->obuf = vio_fifo_new(obuf_size) ;
vio_fifo_set_end_mark(vf->obuf) ;
vf->depth_mark = vio->depth_mark + 1 ;
@@ -595,7 +596,7 @@ uty_close(vty_io vio, const char* reason, bool curtains)
/* Can dispose of these now -- leave vin/vout for final disposition */
vio->vty->exec = cmd_exec_free(vio->vty->exec) ;
- vio->ebuf = vio_fifo_reset(vio->ebuf, free_it) ;
+ vio->ebuf = vio_fifo_free(vio->ebuf) ;
/* Command loop is not running, so can place on death watch for final
* disposition.
@@ -638,11 +639,11 @@ uty_dispose(vty_io vio)
vio->vout = NULL ;
/* Remainder of contents of the vio */
- vio->ebuf = vio_fifo_reset(vio->ebuf, free_it) ;
+ vio->ebuf = vio_fifo_free(vio->ebuf) ;
/* Really cannot be a monitor any more ! */
assert(!vio->monitor) ;
- vio->mbuf = vio_fifo_reset(vio->mbuf, free_it) ;
+ vio->mbuf = vio_fifo_free(vio->mbuf) ;
XFREE(MTYPE_VTY, vio) ;
@@ -1222,9 +1223,9 @@ uty_vf_free(vio_vf vf)
assert(vf->cli == NULL) ;
- vf->ibuf = vio_fifo_reset(vf->ibuf, free_it) ;
+ vf->ibuf = vio_fifo_free(vf->ibuf) ;
vf->cl = qs_reset(vf->cl, free_it) ;
- vf->obuf = vio_fifo_reset(vf->obuf, free_it) ;
+ vf->obuf = vio_fifo_free(vf->obuf) ;
vf->context = cmd_context_free(vf->context, false) ; /* not a copy */
diff --git a/lib/vty_io_basic.c b/lib/vty_io_basic.c
index 3239c893..1d40c210 100644
--- a/lib/vty_io_basic.c
+++ b/lib/vty_io_basic.c
@@ -20,7 +20,7 @@
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
-
+#include "misc.h"
#include "vty_io_basic.h"
#include "vty_local.h"
diff --git a/lib/vty_io_file.c b/lib/vty_io_file.c
index 2322114a..01a92a2d 100644
--- a/lib/vty_io_file.c
+++ b/lib/vty_io_file.c
@@ -368,12 +368,12 @@ uty_fifo_command_line(vio_vf vf, cmd_action action)
while (1)
{
char* s, * p, * e ;
- size_t have ;
+ ulen have ;
ulen len ;
bool eol ;
/* Get what we can from the fifo */
- s = vio_fifo_get(vf->ibuf, &have) ;
+ have = vio_fifo_get(vf->ibuf) ;
/* If fifo is empty, may be last line before eof, eof or waiting */
if (have == 0)
@@ -399,7 +399,7 @@ uty_fifo_command_line(vio_vf vf, cmd_action action)
* This means that we cope with "\r\n" line terminators. But not
* anything more exotic.
*/
- p = s ;
+ p = s = vio_fifo_get_ptr(vf->ibuf) ;
e = s + have ; /* have != 0 */
eol = false ;
@@ -956,6 +956,8 @@ uty_pipe_open_complete(vio_vf vf, pid_t pid, int ret_fd, vio_vf slave)
if (!vf->blocking)
vio_vfd_set_read_action(vf->pr_vfd, uty_pipe_return_ready) ;
+ vio_vfd_set_read_timeout_action(vf->pr_vfd, uty_pipe_return_timeout) ;
+
/* Configure master/slave relationship. */
slave->pr_master = vf ;
vf->pr_slave = slave ;
diff --git a/lib/vty_io_term.c b/lib/vty_io_term.c
index 2c9cb643..0a1efc72 100644
--- a/lib/vty_io_term.c
+++ b/lib/vty_io_term.c
@@ -20,7 +20,6 @@
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
-#include "zconfig.h"
#include "misc.h"
#include "vty_local.h"
@@ -579,7 +578,7 @@ uty_term_read_timeout(vio_timer timer, void* action_info)
VTY_ASSERT_LOCKED() ;
vf->vin_state = vf_timed_out ;
- keystroke_stream_set_eof(vf->cli->key_stream, true) ;
+ keystroke_stream_set_eof(vf->cli->key_stream, true) ; /* timed out */
vf->cli->paused = false ;
@@ -773,8 +772,7 @@ uty_term_write(vio_vf vf)
vty_cli cli = vf->cli ;
utw_ret_t ret ;
int did ;
- size_t have, take ;
- char* src ;
+ ulen have, take ;
VTY_ASSERT_LOCKED() ;
@@ -851,15 +849,15 @@ uty_term_write(vio_vf vf)
*/
vio_fifo_set_hold_mark(vf->obuf) ; /* released in uty_term_write_lc() */
- src = vio_fifo_get(vf->obuf, &have) ;
+ have = vio_fifo_get(vf->obuf) ;
while (1)
{
- take = vio_lc_append(cli->olc, src, have) ;
+ take = vio_lc_append(cli->olc, vio_fifo_get_ptr(vf->obuf), have) ;
if (take == 0)
break ;
- src = vio_fifo_step_get(vf->obuf, &have, take) ;
+ have = vio_fifo_step_get(vf->obuf, take) ;
if (have == 0)
break ;
diff --git a/lib/vty_log.c b/lib/vty_log.c
index edb3291b..080f86a3 100644
--- a/lib/vty_log.c
+++ b/lib/vty_log.c
@@ -110,7 +110,7 @@ uty_set_monitor(vty_io vio, bool on)
vio->mon_kick = false ;
if (vio->mbuf == NULL)
- vio->mbuf = vio_fifo_init_new(NULL, 8 * 1024) ;
+ vio->mbuf = vio_fifo_new(8 * 1024) ;
sdl_push(vio_monitor_list, vio, mon_list) ;
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 6f2cd531..56959db0 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -32,7 +32,10 @@
/* master list of work_queues */
static struct list work_queues;
-#define WORK_QUEUE_MIN_GRANULARITY 1
+enum {
+ WQ_MIN_GRANULARITY = 1,
+ WQ_HYSTERESIS_FACTOR = 4,
+} ;
static void
work_queue_item_free (struct work_queue *wq, struct work_queue_item *item)
@@ -62,7 +65,7 @@ work_queue_new (struct thread_master *m, const char *queue_name)
listnode_add (&work_queues, new);
- new->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY;
+ new->cycles.granularity = WQ_MIN_GRANULARITY;
/* Default values, can be overriden by caller */
new->spec.hold = WORK_QUEUE_DEFAULT_HOLD;
@@ -335,7 +338,7 @@ work_queue_run (struct thread *thread)
*
* Best: starts low, can only increase
*
- * Granularity: starts at WORK_QUEUE_MIN_GRANULARITY, can be decreased
+ * Granularity: starts at WQ_MIN_GRANULARITY, can be decreased
* if we run to end of time slot, can increase otherwise
* by a small factor.
*
@@ -344,7 +347,7 @@ work_queue_run (struct thread *thread)
* daemon has been running a long time.
*/
if (wq->cycles.granularity == 0)
- wq->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY;
+ wq->cycles.granularity = WQ_MIN_GRANULARITY;
next = wq->head ;
while (next != NULL)
@@ -420,27 +423,25 @@ work_queue_run (struct thread *thread)
stats:
-#define WQ_HYSTERIS_FACTOR 2
-
/* we yielded, check whether granularity should be reduced */
if (yielded && (cycles < wq->cycles.granularity))
{
wq->cycles.granularity = ((cycles > 0) ? cycles
- : WORK_QUEUE_MIN_GRANULARITY);
+ : WQ_MIN_GRANULARITY);
}
-
- if (cycles >= (wq->cycles.granularity))
+ /* otherwise, should granularity increase? */
+ else if (cycles >= (wq->cycles.granularity))
{
if (cycles > wq->cycles.best)
wq->cycles.best = cycles;
- /* along with yielded check, provides hysteris for granularity */
- if (cycles > (wq->cycles.granularity * WQ_HYSTERIS_FACTOR * 2))
- wq->cycles.granularity *= WQ_HYSTERIS_FACTOR; /* quick ramp-up */
- else if (cycles > (wq->cycles.granularity * WQ_HYSTERIS_FACTOR))
- wq->cycles.granularity += WQ_HYSTERIS_FACTOR;
+ /* along with yielded check, provides hysteresis for granularity */
+ if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR
+ * WQ_HYSTERESIS_FACTOR))
+ wq->cycles.granularity *= WQ_HYSTERESIS_FACTOR; /* quick ramp-up */
+ else if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR))
+ wq->cycles.granularity += WQ_HYSTERESIS_FACTOR;
}
-#undef WQ_HYSTERIS_FACTOR
wq->runs++;
wq->cycles.total += cycles;
diff --git a/lib/workqueue.h b/lib/workqueue.h
index d9f32a04..15e08804 100644
--- a/lib/workqueue.h
+++ b/lib/workqueue.h
@@ -27,7 +27,7 @@
#include "misc.h"
/* Hold time for the initial schedule of a queue run, in millisec */
-#define WORK_QUEUE_DEFAULT_HOLD 50
+enum { WORK_QUEUE_DEFAULT_HOLD = 50 } ;
/* action value, for use by item processor and item error handlers */
typedef enum
diff --git a/lib/zassert.h b/lib/zassert.h
index a12464fe..84e2c819 100644
--- a/lib/zassert.h
+++ b/lib/zassert.h
@@ -5,8 +5,8 @@
#ifndef _QUAGGA_ASSERT_H
#define _QUAGGA_ASSERT_H
-#include "confirm.h"
#include "misc.h"
+#include "confirm.h"
extern void _zlog_assert_failed (const char *assertion, const char *file,
unsigned int line, const char *function)
diff --git a/lib/zclient.c b/lib/zclient.c
index f365a1aa..6803aa4a 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -428,12 +428,12 @@ zclient_start (struct zclient *zclient)
/* Create read thread. */
zclient_event (ZCLIENT_READ, zclient);
- /* We need interface information. */
- zebra_message_send (zclient, ZEBRA_INTERFACE_ADD);
-
/* We need router-id information. */
zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD);
+ /* We need interface information. */
+ zebra_message_send (zclient, ZEBRA_INTERFACE_ADD);
+
/* Flush all redistribute request. */
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
if (i != zclient->redist_default && zclient->redist[i])
diff --git a/lib/zclient.h b/lib/zclient.h
index 394407eb..17f4e317 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -7,12 +7,12 @@
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
- *
+ *
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
@@ -25,6 +25,7 @@
/* For struct interface and struct connected. */
#include "if.h"
#include "qpnexus.h"
+#include "prefix.h"
/* For input/output buffer to zebra. */
#define ZEBRA_MAX_PACKET_SIZ 4096
@@ -161,7 +162,7 @@ extern struct interface *zebra_interface_state_read (struct stream *s);
extern struct connected *zebra_interface_address_read (int, struct stream *);
extern void zebra_interface_if_set_value (struct stream *, struct interface *);
extern void zebra_router_id_update_read (struct stream *s, struct prefix *rid);
-extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *,
+extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *,
struct zapi_ipv4 *);
#ifdef HAVE_IPV6
@@ -186,7 +187,7 @@ struct zapi_ipv6
u_int32_t metric;
};
-extern int zapi_ipv6_route (u_char cmd, struct zclient *zclient,
+extern int zapi_ipv6_route (u_char cmd, struct zclient *zclient,
struct prefix_ipv6 *p, struct zapi_ipv6 *api);
#endif /* HAVE_IPV6 */
diff --git a/lib/zconfig.h b/lib/zconfig.h
index afde09c6..f1bd6f78 100644
--- a/lib/zconfig.h
+++ b/lib/zconfig.h
@@ -25,10 +25,18 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "config.h"
-#if _GNU_SOURCE
-#include <features.h>
+#undef _THREAD_SAFE
+#define _THREAD_SAFE 1
+
+#undef _REENTRANT
+#define _REENTRANT 1
+
+#ifdef _FEATURES_H
+#error Features defined
#endif
+#include <features.h>
+
#endif /* HAVE_CONFIG_H */
#endif /* _ZEBRA_CONFIG_H */
diff --git a/lib/zebra.h b/lib/zebra.h
index 52e5d571..031fe85c 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -35,6 +35,7 @@ typedef unsigned char u_int8_t;
typedef int socklen_t;
#endif /* HAVE_SOCKLEN_T */
+#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -42,7 +43,6 @@ typedef int socklen_t;
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
-#include <string.h>
#include <pwd.h>
#include <grp.h>
#ifdef HAVE_STROPTS_H