[PATCH 1/4] stringbuf: A string buffer implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Consecutive calls to printk are non-atomic, which leads to various
implementations for accumulating strings which can be printed in one call.
This is a generic string buffer which can also be used for non-printk
purposes.  There is no sb_scanf implementation yet as I haven't identified
a user for it.

Signed-off-by: Matthew Wilcox <[email protected]>
---
 include/linux/stringbuf.h |   77 ++++++++++++++++++++++++++++++++++++++++
 lib/Makefile              |    2 +-
 lib/stringbuf.c           |   85 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 163 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/stringbuf.h
 create mode 100644 lib/stringbuf.c

diff --git a/include/linux/stringbuf.h b/include/linux/stringbuf.h
new file mode 100644
index 0000000..c030bc6
--- /dev/null
+++ b/include/linux/stringbuf.h
@@ -0,0 +1,77 @@
+/*
+ * An auto-expanding string buffer.  There's no sb_alloc because you really
+ * want to allocate it on the stack or embed it in another structure.
+ *
+ * No locking is performed for you; callers are expected to handle locking
+ * themselves if necessary.
+ */
+
+#include <stdarg.h>
+#include <linux/string.h>
+
+/*
+ * 'buf' is the string and may be accessed directly.
+ * 'len' is the number of bytes excluding the NUL terminator.  It may
+ *   also be accessed directly, but note that a freshly-initialised
+ *   stringbuf has a NULL buf, and a len of 0.
+ * 'alloc' is the number of bytes currently allocated to 'buf'.  It
+ *   probably shouldn't be accessed directly.  If you find yourself
+ *   having to, maybe you need to add more functionality to the
+ *   stringbuf code.
+ */
+struct stringbuf {
+	char *buf;
+	int len;
+	int alloc;
+};
+
+/*
+ * Returns a negative errno if an error has been found with this stringbuf,
+ * or 0 if no error has occurred.  If an error has occurred, sb->buf
+ * contains a suitable description of the error
+ */
+static inline int sb_error(struct stringbuf *sb)
+{
+	return sb->alloc < 0 ? sb->alloc : 0;
+}
+
+/*
+ * Initialise a newly-allocated stringbuf
+ */
+static inline void sb_init(struct stringbuf *sb)
+{
+	memset(sb, 0, sizeof(*sb));
+}
+
+/*
+ * Free the contents of a stringbuf, not the stringbuf itself.  The
+ * stringbuf is then reinitialised so it can be reused, or sb_free can
+ * be called on it multiple times.
+ */
+static inline void sb_free(struct stringbuf *sb)
+{
+	if (sb->alloc > 0)
+		kfree(sb->buf);
+	sb_init(sb);
+}
+
+extern void sb_printf(struct stringbuf *sb, gfp_t gfp, const char *fmt, ...)
+	__attribute__((format(printf, 3, 4)));
+#if 0
+/* Waiting for a user to show up */
+extern void sb_vprintf(struct stringbuf *sb, gfp_t gfp, const char *fmt,
+			va_list args) __attribute__((format(printf, 3, 0)));
+#endif
+
+/*
+ * Convert the stringbuf to a string.  It is the caller's responsibility
+ * to free the string.  The stringbuf is then ready to be reused.
+ */
+static inline char *sb_to_string(struct stringbuf *sb)
+{
+	char *s = sb->buf;
+	if (sb_error(sb))
+		s = kstrdup(s, GFP_ATOMIC);
+	sb_init(sb);
+	return s;
+}
diff --git a/lib/Makefile b/lib/Makefile
index 3a0983b..f075389 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -14,7 +14,7 @@ lib-$(CONFIG_SMP) += cpumask.o
 lib-y	+= kobject.o kref.o klist.o
 
 obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
-	 bust_spinlocks.o hexdump.o kasprintf.o
+	 bust_spinlocks.o hexdump.o kasprintf.o stringbuf.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/stringbuf.c b/lib/stringbuf.c
new file mode 100644
index 0000000..b4e59f4
--- /dev/null
+++ b/lib/stringbuf.c
@@ -0,0 +1,85 @@
+/*
+ * stringbuf.c
+ *
+ * Copyright (c) 2007 Intel Corporation
+ * By Matthew Wilcox <[email protected]>
+ *
+ * Released under the terms of the GNU GPL, version 2.
+ *
+ * A simple automatically expanding string.  I'm not opposed to adding
+ * more functions to this (eg sb_scanf, sb_insert, sb_delete, sb_strchr, etc),
+ * but I have no need for them right now, so I haven't added them.
+ */
+
+#include <stdarg.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/stringbuf.h>
+
+#define INITIAL_SIZE 128
+#define ERR_STRING "out of memory"
+
+/*
+ * Not currently used outside this file, but separated from sb_printf
+ * for when someone needs it.
+ */
+static void sb_vprintf(struct stringbuf *sb, gfp_t gfp, const char *format, va_list args)
+{
+	char *s;
+	int size, newlen;
+
+	if (sb->alloc == -ENOMEM)
+		return;
+	if (sb->alloc == 0) {
+		sb->buf = kmalloc(INITIAL_SIZE, gfp);
+		if (!sb->buf) 
+			goto nomem;
+		sb->alloc = INITIAL_SIZE;
+	}
+
+	s = sb->buf + sb->len;
+	size = vsnprintf(s, sb->alloc - sb->len, format, args);
+
+	sb->len += size;
+	if (likely(sb->len < sb->alloc))
+		return;
+
+	/*
+	 * Ensure we always grow the buffer by at least 1.5x.  slab and
+	 * slub already enforce this, but slob will happily allocate
+	 * sizes down to two bytes in granularity
+	 */
+	newlen = max(sb->len + 1, sb->alloc + sb->alloc / 2);
+	s = krealloc(sb->buf, newlen, gfp);
+	if (!s)
+		goto nomem;
+	sb->buf = s;
+	sb->alloc = ksize(s);
+
+	/* Point to the end of the old string since we already updated ->len */
+	s += sb->len - size;
+	vsprintf(s, format, args);
+	return;
+
+ nomem:
+	kfree(sb->buf);
+	sb->buf = ERR_STRING;
+	sb->len = sizeof(ERR_STRING);
+	sb->alloc = -ENOMEM;
+}
+/* When we get our first modular user, delete this comment
+EXPORT_SYMBOL(sb_vprintf);
+*/
+
+void sb_printf(struct stringbuf *sb, gfp_t gfp, const char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	sb_vprintf(sb, gfp, format, args);
+	va_end(args);
+}
+EXPORT_SYMBOL(sb_printf);
-- 
1.5.3.4

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux