From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pg1-f195.google.com (mail-pg1-f195.google.com [209.85.215.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 7A32421196839 for ; Thu, 29 Nov 2018 19:29:29 -0800 (PST) Received: by mail-pg1-f195.google.com with SMTP id w6so1872373pgl.6 for ; Thu, 29 Nov 2018 19:29:29 -0800 (PST) Date: Thu, 29 Nov 2018 19:29:24 -0800 From: Luis Chamberlain Subject: Re: [RFC v3 03/19] kunit: test: add string_stream a std::stream like string builder Message-ID: <20181130032924.GH18410@garbanzo.do-not-panic.com> References: <20181128193636.254378-1-brendanhiggins@google.com> <20181128193636.254378-4-brendanhiggins@google.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20181128193636.254378-4-brendanhiggins@google.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" To: Brendan Higgins , Petr Mladek Cc: brakmo@fb.com, dri-devel@lists.freedesktop.org, linux-kselftest@vger.kernel.org, shuah@kernel.org, robh@kernel.org, frowand.list@gmail.com, linux-nvdimm@lists.01.org, richard@nod.at, knut.omang@oracle.com, kieran.bingham@ideasonboard.com, joel@jms.id.au, jdike@addtoit.com, Tim.Bird@sony.com, keescook@google.com, linux-um@lists.infradead.org, rostedt@goodmis.org, julia.lawall@lip6.fr, kunit-dev@googlegroups.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, daniel@ffwll.ch, mpe@ellerman.id.au, joe@perches.com, khilman@baylibre.com List-ID: On Wed, Nov 28, 2018 at 11:36:20AM -0800, Brendan Higgins wrote: > A number of test features need to do pretty complicated string printing > where it may not be possible to rely on a single preallocated string > with parameters. > > So provide a library for constructing the string as you go similar to > C++'s std::string. Hrm, what's the potential for such thing actually being eventually generically useful for printk folks, I wonder? Petr? Luis > > Signed-off-by: Brendan Higgins > --- > include/kunit/string-stream.h | 44 ++++++++++ > kunit/Makefile | 3 +- > kunit/string-stream.c | 149 ++++++++++++++++++++++++++++++++++ > 3 files changed, 195 insertions(+), 1 deletion(-) > create mode 100644 include/kunit/string-stream.h > create mode 100644 kunit/string-stream.c > > diff --git a/include/kunit/string-stream.h b/include/kunit/string-stream.h > new file mode 100644 > index 0000000000000..933ed5740cf07 > --- /dev/null > +++ b/include/kunit/string-stream.h > @@ -0,0 +1,44 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#ifndef _KUNIT_STRING_STREAM_H > +#define _KUNIT_STRING_STREAM_H > + > +#include > +#include > +#include > +#include > + > +struct string_stream_fragment { > + struct list_head node; > + char *fragment; > +}; > + > +struct string_stream { > + size_t length; > + struct list_head fragments; > + > + /* length and fragments are protected by this lock */ > + spinlock_t lock; > + struct kref refcount; > + int (*add)(struct string_stream *this, const char *fmt, ...); > + int (*vadd)(struct string_stream *this, const char *fmt, va_list args); > + char *(*get_string)(struct string_stream *this); > + void (*clear)(struct string_stream *this); > + bool (*is_empty)(struct string_stream *this); > +}; > + > +struct string_stream *new_string_stream(void); > + > +void destroy_string_stream(struct string_stream *stream); > + > +void string_stream_get(struct string_stream *stream); > + > +int string_stream_put(struct string_stream *stream); > + > +#endif /* _KUNIT_STRING_STREAM_H */ > diff --git a/kunit/Makefile b/kunit/Makefile > index 5efdc4dea2c08..275b565a0e81f 100644 > --- a/kunit/Makefile > +++ b/kunit/Makefile > @@ -1 +1,2 @@ > -obj-$(CONFIG_KUNIT) += test.o > +obj-$(CONFIG_KUNIT) += test.o \ > + string-stream.o > diff --git a/kunit/string-stream.c b/kunit/string-stream.c > new file mode 100644 > index 0000000000000..1e7efa630cc35 > --- /dev/null > +++ b/kunit/string-stream.c > @@ -0,0 +1,149 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#include > +#include > +#include > + > +static int string_stream_vadd(struct string_stream *this, > + const char *fmt, > + va_list args) > +{ > + struct string_stream_fragment *fragment; > + int len; > + va_list args_for_counting; > + unsigned long flags; > + > + /* Make a copy because `vsnprintf` could change it */ > + va_copy(args_for_counting, args); > + > + /* Need space for null byte. */ > + len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1; > + > + va_end(args_for_counting); > + > + fragment = kmalloc(sizeof(*fragment), GFP_KERNEL); > + if (!fragment) > + return -ENOMEM; > + > + fragment->fragment = kmalloc(len, GFP_KERNEL); > + if (!fragment->fragment) { > + kfree(fragment); > + return -ENOMEM; > + } > + > + len = vsnprintf(fragment->fragment, len, fmt, args); > + spin_lock_irqsave(&this->lock, flags); > + this->length += len; > + list_add_tail(&fragment->node, &this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + return 0; > +} > + > +static int string_stream_add(struct string_stream *this, const char *fmt, ...) > +{ > + va_list args; > + int result; > + > + va_start(args, fmt); > + result = string_stream_vadd(this, fmt, args); > + va_end(args); > + return result; > +} > + > +static void string_stream_clear(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment, *fragment_safe; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry_safe(fragment, > + fragment_safe, > + &this->fragments, > + node) { > + list_del(&fragment->node); > + kfree(fragment->fragment); > + kfree(fragment); > + } > + this->length = 0; > + spin_unlock_irqrestore(&this->lock, flags); > +} > + > +static char *string_stream_get_string(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment; > + size_t buf_len = this->length + 1; /* +1 for null byte. */ > + char *buf; > + unsigned long flags; > + > + buf = kzalloc(buf_len, GFP_KERNEL); > + if (!buf) > + return NULL; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry(fragment, &this->fragments, node) > + strlcat(buf, fragment->fragment, buf_len); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return buf; > +} > + > +static bool string_stream_is_empty(struct string_stream *this) > +{ > + bool is_empty; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + is_empty = list_empty(&this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return is_empty; > +} > + > +void destroy_string_stream(struct string_stream *stream) > +{ > + stream->clear(stream); > + kfree(stream); > +} > + > +static void string_stream_destroy(struct kref *kref) > +{ > + struct string_stream *stream = container_of(kref, > + struct string_stream, > + refcount); > + destroy_string_stream(stream); > +} > + > +struct string_stream *new_string_stream(void) > +{ > + struct string_stream *stream = kzalloc(sizeof(*stream), GFP_KERNEL); > + > + if (!stream) > + return NULL; > + > + INIT_LIST_HEAD(&stream->fragments); > + spin_lock_init(&stream->lock); > + kref_init(&stream->refcount); > + stream->add = string_stream_add; > + stream->vadd = string_stream_vadd; > + stream->get_string = string_stream_get_string; > + stream->clear = string_stream_clear; > + stream->is_empty = string_stream_is_empty; > + return stream; > +} > + > +void string_stream_get(struct string_stream *stream) > +{ > + kref_get(&stream->refcount); > +} > + > +int string_stream_put(struct string_stream *stream) > +{ > + return kref_put(&stream->refcount, &string_stream_destroy); > +} > + > -- > 2.20.0.rc0.387.gc7a69e6b6c-goog > _______________________________________________ Linux-nvdimm mailing list Linux-nvdimm@lists.01.org https://lists.01.org/mailman/listinfo/linux-nvdimm From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.5 required=3.0 tests=INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,USER_AGENT_MUTT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3B649C04EB9 for ; Fri, 30 Nov 2018 03:29:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id ECE8220868 for ; Fri, 30 Nov 2018 03:29:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org ECE8220868 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=kernel.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726598AbeK3OhT (ORCPT ); Fri, 30 Nov 2018 09:37:19 -0500 Received: from mail-pf1-f193.google.com ([209.85.210.193]:44990 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726161AbeK3OhT (ORCPT ); Fri, 30 Nov 2018 09:37:19 -0500 Received: by mail-pf1-f193.google.com with SMTP id u6so2065695pfh.11; Thu, 29 Nov 2018 19:29:29 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=lIzaK+sk9pQb4ZhnXD8UfV9hzQIJjkgEAqdvY5i14Lk=; b=KOi9dCIeqy+SWyuwCANIyDacdG60f9dnJwmh68HYwRBD8KvglFahvxs/xxjFMGIIYD zdbovWU0Qqe/u/tOjM3UW2GH5Ekcluyh6twu4ZHwoeDOKHvI3rvLa7Yk+Pkix8sJzWFI WmzEtRZSIAQ9kKVRlKkGKwE9jovcTW197wIXh9tzNVfix4TzjYn+6ZBlEtoc1XeuQUy8 457RRrcu5+HXzcj4acM8394oGr9v871186Mg0R0xsnFIoLAYL1hv9n8AfbzlbnLyOKDu ptAzHu1XjukHf+aOA6cKp3fBLCQiBgeoC0GBUdUMpqZh+RFWCCF823nXJsUx59IkBMdw IseA== X-Gm-Message-State: AA+aEWZwF3r5KoY86hM9VF5T6FHttRAgcI2916x2Am3I9O7uU0Wb0p2o 7ATyE7yDKY4P9LE1mQkm1ME= X-Google-Smtp-Source: AFSGD/U1eE9mquOFWmyOAJjBxqxJJ2LAaTItoJ/3Pvo68Awio2SgvjvKkTu3Li1nwQvlmxa17c/7iA== X-Received: by 2002:a63:f141:: with SMTP id o1mr2306635pgk.134.1543548568881; Thu, 29 Nov 2018 19:29:28 -0800 (PST) Received: from garbanzo.do-not-panic.com (c-73-71-40-85.hsd1.ca.comcast.net. [73.71.40.85]) by smtp.gmail.com with ESMTPSA id o8sm11644059pfa.42.2018.11.29.19.29.25 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 29 Nov 2018 19:29:27 -0800 (PST) Received: by garbanzo.do-not-panic.com (sSMTP sendmail emulation); Thu, 29 Nov 2018 19:29:24 -0800 Date: Thu, 29 Nov 2018 19:29:24 -0800 From: Luis Chamberlain To: Brendan Higgins , Petr Mladek Cc: gregkh@linuxfoundation.org, keescook@google.com, shuah@kernel.org, joel@jms.id.au, mpe@ellerman.id.au, joe@perches.com, brakmo@fb.com, rostedt@goodmis.org, Tim.Bird@sony.com, khilman@baylibre.com, julia.lawall@lip6.fr, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, linux-kernel@vger.kernel.org, jdike@addtoit.com, richard@nod.at, linux-um@lists.infradead.org, daniel@ffwll.ch, dri-devel@lists.freedesktop.org, robh@kernel.org, dan.j.williams@intel.com, linux-nvdimm@lists.01.org, kieran.bingham@ideasonboard.com, frowand.list@gmail.com, knut.omang@oracle.com Subject: Re: [RFC v3 03/19] kunit: test: add string_stream a std::stream like string builder Message-ID: <20181130032924.GH18410@garbanzo.do-not-panic.com> References: <20181128193636.254378-1-brendanhiggins@google.com> <20181128193636.254378-4-brendanhiggins@google.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20181128193636.254378-4-brendanhiggins@google.com> User-Agent: Mutt/1.10.1 (2018-07-13) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, Nov 28, 2018 at 11:36:20AM -0800, Brendan Higgins wrote: > A number of test features need to do pretty complicated string printing > where it may not be possible to rely on a single preallocated string > with parameters. > > So provide a library for constructing the string as you go similar to > C++'s std::string. Hrm, what's the potential for such thing actually being eventually generically useful for printk folks, I wonder? Petr? Luis > > Signed-off-by: Brendan Higgins > --- > include/kunit/string-stream.h | 44 ++++++++++ > kunit/Makefile | 3 +- > kunit/string-stream.c | 149 ++++++++++++++++++++++++++++++++++ > 3 files changed, 195 insertions(+), 1 deletion(-) > create mode 100644 include/kunit/string-stream.h > create mode 100644 kunit/string-stream.c > > diff --git a/include/kunit/string-stream.h b/include/kunit/string-stream.h > new file mode 100644 > index 0000000000000..933ed5740cf07 > --- /dev/null > +++ b/include/kunit/string-stream.h > @@ -0,0 +1,44 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#ifndef _KUNIT_STRING_STREAM_H > +#define _KUNIT_STRING_STREAM_H > + > +#include > +#include > +#include > +#include > + > +struct string_stream_fragment { > + struct list_head node; > + char *fragment; > +}; > + > +struct string_stream { > + size_t length; > + struct list_head fragments; > + > + /* length and fragments are protected by this lock */ > + spinlock_t lock; > + struct kref refcount; > + int (*add)(struct string_stream *this, const char *fmt, ...); > + int (*vadd)(struct string_stream *this, const char *fmt, va_list args); > + char *(*get_string)(struct string_stream *this); > + void (*clear)(struct string_stream *this); > + bool (*is_empty)(struct string_stream *this); > +}; > + > +struct string_stream *new_string_stream(void); > + > +void destroy_string_stream(struct string_stream *stream); > + > +void string_stream_get(struct string_stream *stream); > + > +int string_stream_put(struct string_stream *stream); > + > +#endif /* _KUNIT_STRING_STREAM_H */ > diff --git a/kunit/Makefile b/kunit/Makefile > index 5efdc4dea2c08..275b565a0e81f 100644 > --- a/kunit/Makefile > +++ b/kunit/Makefile > @@ -1 +1,2 @@ > -obj-$(CONFIG_KUNIT) += test.o > +obj-$(CONFIG_KUNIT) += test.o \ > + string-stream.o > diff --git a/kunit/string-stream.c b/kunit/string-stream.c > new file mode 100644 > index 0000000000000..1e7efa630cc35 > --- /dev/null > +++ b/kunit/string-stream.c > @@ -0,0 +1,149 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#include > +#include > +#include > + > +static int string_stream_vadd(struct string_stream *this, > + const char *fmt, > + va_list args) > +{ > + struct string_stream_fragment *fragment; > + int len; > + va_list args_for_counting; > + unsigned long flags; > + > + /* Make a copy because `vsnprintf` could change it */ > + va_copy(args_for_counting, args); > + > + /* Need space for null byte. */ > + len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1; > + > + va_end(args_for_counting); > + > + fragment = kmalloc(sizeof(*fragment), GFP_KERNEL); > + if (!fragment) > + return -ENOMEM; > + > + fragment->fragment = kmalloc(len, GFP_KERNEL); > + if (!fragment->fragment) { > + kfree(fragment); > + return -ENOMEM; > + } > + > + len = vsnprintf(fragment->fragment, len, fmt, args); > + spin_lock_irqsave(&this->lock, flags); > + this->length += len; > + list_add_tail(&fragment->node, &this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + return 0; > +} > + > +static int string_stream_add(struct string_stream *this, const char *fmt, ...) > +{ > + va_list args; > + int result; > + > + va_start(args, fmt); > + result = string_stream_vadd(this, fmt, args); > + va_end(args); > + return result; > +} > + > +static void string_stream_clear(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment, *fragment_safe; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry_safe(fragment, > + fragment_safe, > + &this->fragments, > + node) { > + list_del(&fragment->node); > + kfree(fragment->fragment); > + kfree(fragment); > + } > + this->length = 0; > + spin_unlock_irqrestore(&this->lock, flags); > +} > + > +static char *string_stream_get_string(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment; > + size_t buf_len = this->length + 1; /* +1 for null byte. */ > + char *buf; > + unsigned long flags; > + > + buf = kzalloc(buf_len, GFP_KERNEL); > + if (!buf) > + return NULL; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry(fragment, &this->fragments, node) > + strlcat(buf, fragment->fragment, buf_len); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return buf; > +} > + > +static bool string_stream_is_empty(struct string_stream *this) > +{ > + bool is_empty; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + is_empty = list_empty(&this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return is_empty; > +} > + > +void destroy_string_stream(struct string_stream *stream) > +{ > + stream->clear(stream); > + kfree(stream); > +} > + > +static void string_stream_destroy(struct kref *kref) > +{ > + struct string_stream *stream = container_of(kref, > + struct string_stream, > + refcount); > + destroy_string_stream(stream); > +} > + > +struct string_stream *new_string_stream(void) > +{ > + struct string_stream *stream = kzalloc(sizeof(*stream), GFP_KERNEL); > + > + if (!stream) > + return NULL; > + > + INIT_LIST_HEAD(&stream->fragments); > + spin_lock_init(&stream->lock); > + kref_init(&stream->refcount); > + stream->add = string_stream_add; > + stream->vadd = string_stream_vadd; > + stream->get_string = string_stream_get_string; > + stream->clear = string_stream_clear; > + stream->is_empty = string_stream_is_empty; > + return stream; > +} > + > +void string_stream_get(struct string_stream *stream) > +{ > + kref_get(&stream->refcount); > +} > + > +int string_stream_put(struct string_stream *stream) > +{ > + return kref_put(&stream->refcount, &string_stream_destroy); > +} > + > -- > 2.20.0.rc0.387.gc7a69e6b6c-goog > From mboxrd@z Thu Jan 1 00:00:00 1970 From: mcgrof at kernel.org (Luis Chamberlain) Date: Thu, 29 Nov 2018 19:29:24 -0800 Subject: [RFC v3 03/19] kunit: test: add string_stream a std::stream like string builder In-Reply-To: <20181128193636.254378-4-brendanhiggins@google.com> References: <20181128193636.254378-1-brendanhiggins@google.com> <20181128193636.254378-4-brendanhiggins@google.com> Message-ID: <20181130032924.GH18410@garbanzo.do-not-panic.com> On Wed, Nov 28, 2018 at 11:36:20AM -0800, Brendan Higgins wrote: > A number of test features need to do pretty complicated string printing > where it may not be possible to rely on a single preallocated string > with parameters. > > So provide a library for constructing the string as you go similar to > C++'s std::string. Hrm, what's the potential for such thing actually being eventually generically useful for printk folks, I wonder? Petr? Luis > > Signed-off-by: Brendan Higgins > --- > include/kunit/string-stream.h | 44 ++++++++++ > kunit/Makefile | 3 +- > kunit/string-stream.c | 149 ++++++++++++++++++++++++++++++++++ > 3 files changed, 195 insertions(+), 1 deletion(-) > create mode 100644 include/kunit/string-stream.h > create mode 100644 kunit/string-stream.c > > diff --git a/include/kunit/string-stream.h b/include/kunit/string-stream.h > new file mode 100644 > index 0000000000000..933ed5740cf07 > --- /dev/null > +++ b/include/kunit/string-stream.h > @@ -0,0 +1,44 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#ifndef _KUNIT_STRING_STREAM_H > +#define _KUNIT_STRING_STREAM_H > + > +#include > +#include > +#include > +#include > + > +struct string_stream_fragment { > + struct list_head node; > + char *fragment; > +}; > + > +struct string_stream { > + size_t length; > + struct list_head fragments; > + > + /* length and fragments are protected by this lock */ > + spinlock_t lock; > + struct kref refcount; > + int (*add)(struct string_stream *this, const char *fmt, ...); > + int (*vadd)(struct string_stream *this, const char *fmt, va_list args); > + char *(*get_string)(struct string_stream *this); > + void (*clear)(struct string_stream *this); > + bool (*is_empty)(struct string_stream *this); > +}; > + > +struct string_stream *new_string_stream(void); > + > +void destroy_string_stream(struct string_stream *stream); > + > +void string_stream_get(struct string_stream *stream); > + > +int string_stream_put(struct string_stream *stream); > + > +#endif /* _KUNIT_STRING_STREAM_H */ > diff --git a/kunit/Makefile b/kunit/Makefile > index 5efdc4dea2c08..275b565a0e81f 100644 > --- a/kunit/Makefile > +++ b/kunit/Makefile > @@ -1 +1,2 @@ > -obj-$(CONFIG_KUNIT) += test.o > +obj-$(CONFIG_KUNIT) += test.o \ > + string-stream.o > diff --git a/kunit/string-stream.c b/kunit/string-stream.c > new file mode 100644 > index 0000000000000..1e7efa630cc35 > --- /dev/null > +++ b/kunit/string-stream.c > @@ -0,0 +1,149 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#include > +#include > +#include > + > +static int string_stream_vadd(struct string_stream *this, > + const char *fmt, > + va_list args) > +{ > + struct string_stream_fragment *fragment; > + int len; > + va_list args_for_counting; > + unsigned long flags; > + > + /* Make a copy because `vsnprintf` could change it */ > + va_copy(args_for_counting, args); > + > + /* Need space for null byte. */ > + len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1; > + > + va_end(args_for_counting); > + > + fragment = kmalloc(sizeof(*fragment), GFP_KERNEL); > + if (!fragment) > + return -ENOMEM; > + > + fragment->fragment = kmalloc(len, GFP_KERNEL); > + if (!fragment->fragment) { > + kfree(fragment); > + return -ENOMEM; > + } > + > + len = vsnprintf(fragment->fragment, len, fmt, args); > + spin_lock_irqsave(&this->lock, flags); > + this->length += len; > + list_add_tail(&fragment->node, &this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + return 0; > +} > + > +static int string_stream_add(struct string_stream *this, const char *fmt, ...) > +{ > + va_list args; > + int result; > + > + va_start(args, fmt); > + result = string_stream_vadd(this, fmt, args); > + va_end(args); > + return result; > +} > + > +static void string_stream_clear(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment, *fragment_safe; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry_safe(fragment, > + fragment_safe, > + &this->fragments, > + node) { > + list_del(&fragment->node); > + kfree(fragment->fragment); > + kfree(fragment); > + } > + this->length = 0; > + spin_unlock_irqrestore(&this->lock, flags); > +} > + > +static char *string_stream_get_string(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment; > + size_t buf_len = this->length + 1; /* +1 for null byte. */ > + char *buf; > + unsigned long flags; > + > + buf = kzalloc(buf_len, GFP_KERNEL); > + if (!buf) > + return NULL; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry(fragment, &this->fragments, node) > + strlcat(buf, fragment->fragment, buf_len); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return buf; > +} > + > +static bool string_stream_is_empty(struct string_stream *this) > +{ > + bool is_empty; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + is_empty = list_empty(&this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return is_empty; > +} > + > +void destroy_string_stream(struct string_stream *stream) > +{ > + stream->clear(stream); > + kfree(stream); > +} > + > +static void string_stream_destroy(struct kref *kref) > +{ > + struct string_stream *stream = container_of(kref, > + struct string_stream, > + refcount); > + destroy_string_stream(stream); > +} > + > +struct string_stream *new_string_stream(void) > +{ > + struct string_stream *stream = kzalloc(sizeof(*stream), GFP_KERNEL); > + > + if (!stream) > + return NULL; > + > + INIT_LIST_HEAD(&stream->fragments); > + spin_lock_init(&stream->lock); > + kref_init(&stream->refcount); > + stream->add = string_stream_add; > + stream->vadd = string_stream_vadd; > + stream->get_string = string_stream_get_string; > + stream->clear = string_stream_clear; > + stream->is_empty = string_stream_is_empty; > + return stream; > +} > + > +void string_stream_get(struct string_stream *stream) > +{ > + kref_get(&stream->refcount); > +} > + > +int string_stream_put(struct string_stream *stream) > +{ > + return kref_put(&stream->refcount, &string_stream_destroy); > +} > + > -- > 2.20.0.rc0.387.gc7a69e6b6c-goog > From mboxrd@z Thu Jan 1 00:00:00 1970 From: mcgrof@kernel.org (Luis Chamberlain) Date: Thu, 29 Nov 2018 19:29:24 -0800 Subject: [RFC v3 03/19] kunit: test: add string_stream a std::stream like string builder In-Reply-To: <20181128193636.254378-4-brendanhiggins@google.com> References: <20181128193636.254378-1-brendanhiggins@google.com> <20181128193636.254378-4-brendanhiggins@google.com> Message-ID: <20181130032924.GH18410@garbanzo.do-not-panic.com> Content-Type: text/plain; charset="UTF-8" Message-ID: <20181130032924.DxkVI5XxKGJKAc4CiMZlWzruz2VKyDXYNwnizinMni4@z> On Wed, Nov 28, 2018@11:36:20AM -0800, Brendan Higgins wrote: > A number of test features need to do pretty complicated string printing > where it may not be possible to rely on a single preallocated string > with parameters. > > So provide a library for constructing the string as you go similar to > C++'s std::string. Hrm, what's the potential for such thing actually being eventually generically useful for printk folks, I wonder? Petr? Luis > > Signed-off-by: Brendan Higgins > --- > include/kunit/string-stream.h | 44 ++++++++++ > kunit/Makefile | 3 +- > kunit/string-stream.c | 149 ++++++++++++++++++++++++++++++++++ > 3 files changed, 195 insertions(+), 1 deletion(-) > create mode 100644 include/kunit/string-stream.h > create mode 100644 kunit/string-stream.c > > diff --git a/include/kunit/string-stream.h b/include/kunit/string-stream.h > new file mode 100644 > index 0000000000000..933ed5740cf07 > --- /dev/null > +++ b/include/kunit/string-stream.h > @@ -0,0 +1,44 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#ifndef _KUNIT_STRING_STREAM_H > +#define _KUNIT_STRING_STREAM_H > + > +#include > +#include > +#include > +#include > + > +struct string_stream_fragment { > + struct list_head node; > + char *fragment; > +}; > + > +struct string_stream { > + size_t length; > + struct list_head fragments; > + > + /* length and fragments are protected by this lock */ > + spinlock_t lock; > + struct kref refcount; > + int (*add)(struct string_stream *this, const char *fmt, ...); > + int (*vadd)(struct string_stream *this, const char *fmt, va_list args); > + char *(*get_string)(struct string_stream *this); > + void (*clear)(struct string_stream *this); > + bool (*is_empty)(struct string_stream *this); > +}; > + > +struct string_stream *new_string_stream(void); > + > +void destroy_string_stream(struct string_stream *stream); > + > +void string_stream_get(struct string_stream *stream); > + > +int string_stream_put(struct string_stream *stream); > + > +#endif /* _KUNIT_STRING_STREAM_H */ > diff --git a/kunit/Makefile b/kunit/Makefile > index 5efdc4dea2c08..275b565a0e81f 100644 > --- a/kunit/Makefile > +++ b/kunit/Makefile > @@ -1 +1,2 @@ > -obj-$(CONFIG_KUNIT) += test.o > +obj-$(CONFIG_KUNIT) += test.o \ > + string-stream.o > diff --git a/kunit/string-stream.c b/kunit/string-stream.c > new file mode 100644 > index 0000000000000..1e7efa630cc35 > --- /dev/null > +++ b/kunit/string-stream.c > @@ -0,0 +1,149 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#include > +#include > +#include > + > +static int string_stream_vadd(struct string_stream *this, > + const char *fmt, > + va_list args) > +{ > + struct string_stream_fragment *fragment; > + int len; > + va_list args_for_counting; > + unsigned long flags; > + > + /* Make a copy because `vsnprintf` could change it */ > + va_copy(args_for_counting, args); > + > + /* Need space for null byte. */ > + len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1; > + > + va_end(args_for_counting); > + > + fragment = kmalloc(sizeof(*fragment), GFP_KERNEL); > + if (!fragment) > + return -ENOMEM; > + > + fragment->fragment = kmalloc(len, GFP_KERNEL); > + if (!fragment->fragment) { > + kfree(fragment); > + return -ENOMEM; > + } > + > + len = vsnprintf(fragment->fragment, len, fmt, args); > + spin_lock_irqsave(&this->lock, flags); > + this->length += len; > + list_add_tail(&fragment->node, &this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + return 0; > +} > + > +static int string_stream_add(struct string_stream *this, const char *fmt, ...) > +{ > + va_list args; > + int result; > + > + va_start(args, fmt); > + result = string_stream_vadd(this, fmt, args); > + va_end(args); > + return result; > +} > + > +static void string_stream_clear(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment, *fragment_safe; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry_safe(fragment, > + fragment_safe, > + &this->fragments, > + node) { > + list_del(&fragment->node); > + kfree(fragment->fragment); > + kfree(fragment); > + } > + this->length = 0; > + spin_unlock_irqrestore(&this->lock, flags); > +} > + > +static char *string_stream_get_string(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment; > + size_t buf_len = this->length + 1; /* +1 for null byte. */ > + char *buf; > + unsigned long flags; > + > + buf = kzalloc(buf_len, GFP_KERNEL); > + if (!buf) > + return NULL; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry(fragment, &this->fragments, node) > + strlcat(buf, fragment->fragment, buf_len); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return buf; > +} > + > +static bool string_stream_is_empty(struct string_stream *this) > +{ > + bool is_empty; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + is_empty = list_empty(&this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return is_empty; > +} > + > +void destroy_string_stream(struct string_stream *stream) > +{ > + stream->clear(stream); > + kfree(stream); > +} > + > +static void string_stream_destroy(struct kref *kref) > +{ > + struct string_stream *stream = container_of(kref, > + struct string_stream, > + refcount); > + destroy_string_stream(stream); > +} > + > +struct string_stream *new_string_stream(void) > +{ > + struct string_stream *stream = kzalloc(sizeof(*stream), GFP_KERNEL); > + > + if (!stream) > + return NULL; > + > + INIT_LIST_HEAD(&stream->fragments); > + spin_lock_init(&stream->lock); > + kref_init(&stream->refcount); > + stream->add = string_stream_add; > + stream->vadd = string_stream_vadd; > + stream->get_string = string_stream_get_string; > + stream->clear = string_stream_clear; > + stream->is_empty = string_stream_is_empty; > + return stream; > +} > + > +void string_stream_get(struct string_stream *stream) > +{ > + kref_get(&stream->refcount); > +} > + > +int string_stream_put(struct string_stream *stream) > +{ > + return kref_put(&stream->refcount, &string_stream_destroy); > +} > + > -- > 2.20.0.rc0.387.gc7a69e6b6c-goog > From mboxrd@z Thu Jan 1 00:00:00 1970 From: Luis Chamberlain Subject: Re: [RFC v3 03/19] kunit: test: add string_stream a std::stream like string builder Date: Thu, 29 Nov 2018 19:29:24 -0800 Message-ID: <20181130032924.GH18410@garbanzo.do-not-panic.com> References: <20181128193636.254378-1-brendanhiggins@google.com> <20181128193636.254378-4-brendanhiggins@google.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from mail-pf1-f196.google.com (mail-pf1-f196.google.com [209.85.210.196]) by gabe.freedesktop.org (Postfix) with ESMTPS id 770836E334 for ; Fri, 30 Nov 2018 03:29:29 +0000 (UTC) Received: by mail-pf1-f196.google.com with SMTP id i12so2073352pfo.7 for ; Thu, 29 Nov 2018 19:29:29 -0800 (PST) Content-Disposition: inline In-Reply-To: <20181128193636.254378-4-brendanhiggins@google.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Brendan Higgins , Petr Mladek Cc: brakmo@fb.com, dri-devel@lists.freedesktop.org, linux-kselftest@vger.kernel.org, shuah@kernel.org, frowand.list@gmail.com, linux-nvdimm@lists.01.org, richard@nod.at, knut.omang@oracle.com, kieran.bingham@ideasonboard.com, joel@jms.id.au, jdike@addtoit.com, Tim.Bird@sony.com, keescook@google.com, linux-um@lists.infradead.org, rostedt@goodmis.org, julia.lawall@lip6.fr, dan.j.williams@intel.com, kunit-dev@googlegroups.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, mpe@ellerman.id.au, joe@perches.com, khilman@baylibre.com List-Id: dri-devel@lists.freedesktop.org T24gV2VkLCBOb3YgMjgsIDIwMTggYXQgMTE6MzY6MjBBTSAtMDgwMCwgQnJlbmRhbiBIaWdnaW5z IHdyb3RlOgo+IEEgbnVtYmVyIG9mIHRlc3QgZmVhdHVyZXMgbmVlZCB0byBkbyBwcmV0dHkgY29t cGxpY2F0ZWQgc3RyaW5nIHByaW50aW5nCj4gd2hlcmUgaXQgbWF5IG5vdCBiZSBwb3NzaWJsZSB0 byByZWx5IG9uIGEgc2luZ2xlIHByZWFsbG9jYXRlZCBzdHJpbmcKPiB3aXRoIHBhcmFtZXRlcnMu Cj4gCj4gU28gcHJvdmlkZSBhIGxpYnJhcnkgZm9yIGNvbnN0cnVjdGluZyB0aGUgc3RyaW5nIGFz IHlvdSBnbyBzaW1pbGFyIHRvCj4gQysrJ3Mgc3RkOjpzdHJpbmcuCgpIcm0sIHdoYXQncyB0aGUg cG90ZW50aWFsIGZvciBzdWNoIHRoaW5nIGFjdHVhbGx5IGJlaW5nIGV2ZW50dWFsbHkKZ2VuZXJp Y2FsbHkgdXNlZnVsIGZvciBwcmludGsgZm9sa3MsIEkgd29uZGVyPyBQZXRyPwoKICBMdWlzCgo+ IAo+IFNpZ25lZC1vZmYtYnk6IEJyZW5kYW4gSGlnZ2lucyA8YnJlbmRhbmhpZ2dpbnNAZ29vZ2xl LmNvbT4KPiAtLS0KPiAgaW5jbHVkZS9rdW5pdC9zdHJpbmctc3RyZWFtLmggfCAgNDQgKysrKysr KysrKwo+ICBrdW5pdC9NYWtlZmlsZSAgICAgICAgICAgICAgICB8ICAgMyArLQo+ICBrdW5pdC9z dHJpbmctc3RyZWFtLmMgICAgICAgICB8IDE0OSArKysrKysrKysrKysrKysrKysrKysrKysrKysr KysrKysrCj4gIDMgZmlsZXMgY2hhbmdlZCwgMTk1IGluc2VydGlvbnMoKyksIDEgZGVsZXRpb24o LSkKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGluY2x1ZGUva3VuaXQvc3RyaW5nLXN0cmVhbS5oCj4g IGNyZWF0ZSBtb2RlIDEwMDY0NCBrdW5pdC9zdHJpbmctc3RyZWFtLmMKPiAKPiBkaWZmIC0tZ2l0 IGEvaW5jbHVkZS9rdW5pdC9zdHJpbmctc3RyZWFtLmggYi9pbmNsdWRlL2t1bml0L3N0cmluZy1z dHJlYW0uaAo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMDAwMDAwMC4uOTMz ZWQ1NzQwY2YwNwo+IC0tLSAvZGV2L251bGwKPiArKysgYi9pbmNsdWRlL2t1bml0L3N0cmluZy1z dHJlYW0uaAo+IEBAIC0wLDAgKzEsNDQgQEAKPiArLyogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6 IEdQTC0yLjAgKi8KPiArLyoKPiArICogQysrIHN0cmVhbSBzdHlsZSBzdHJpbmcgYnVpbGRlciB1 c2VkIGluIEtVbml0IGZvciBidWlsZGluZyBtZXNzYWdlcy4KPiArICoKPiArICogQ29weXJpZ2h0 IChDKSAyMDE4LCBHb29nbGUgTExDLgo+ICsgKiBBdXRob3I6IEJyZW5kYW4gSGlnZ2lucyA8YnJl bmRhbmhpZ2dpbnNAZ29vZ2xlLmNvbT4KPiArICovCj4gKwo+ICsjaWZuZGVmIF9LVU5JVF9TVFJJ TkdfU1RSRUFNX0gKPiArI2RlZmluZSBfS1VOSVRfU1RSSU5HX1NUUkVBTV9ICj4gKwo+ICsjaW5j bHVkZSA8bGludXgvdHlwZXMuaD4KPiArI2luY2x1ZGUgPGxpbnV4L3NwaW5sb2NrLmg+Cj4gKyNp bmNsdWRlIDxsaW51eC9rcmVmLmg+Cj4gKyNpbmNsdWRlIDxzdGRhcmcuaD4KPiArCj4gK3N0cnVj dCBzdHJpbmdfc3RyZWFtX2ZyYWdtZW50IHsKPiArCXN0cnVjdCBsaXN0X2hlYWQgbm9kZTsKPiAr CWNoYXIgKmZyYWdtZW50Owo+ICt9Owo+ICsKPiArc3RydWN0IHN0cmluZ19zdHJlYW0gewo+ICsJ c2l6ZV90IGxlbmd0aDsKPiArCXN0cnVjdCBsaXN0X2hlYWQgZnJhZ21lbnRzOwo+ICsKPiArCS8q IGxlbmd0aCBhbmQgZnJhZ21lbnRzIGFyZSBwcm90ZWN0ZWQgYnkgdGhpcyBsb2NrICovCj4gKwlz cGlubG9ja190IGxvY2s7Cj4gKwlzdHJ1Y3Qga3JlZiByZWZjb3VudDsKPiArCWludCAoKmFkZCko c3RydWN0IHN0cmluZ19zdHJlYW0gKnRoaXMsIGNvbnN0IGNoYXIgKmZtdCwgLi4uKTsKPiArCWlu dCAoKnZhZGQpKHN0cnVjdCBzdHJpbmdfc3RyZWFtICp0aGlzLCBjb25zdCBjaGFyICpmbXQsIHZh X2xpc3QgYXJncyk7Cj4gKwljaGFyICooKmdldF9zdHJpbmcpKHN0cnVjdCBzdHJpbmdfc3RyZWFt ICp0aGlzKTsKPiArCXZvaWQgKCpjbGVhcikoc3RydWN0IHN0cmluZ19zdHJlYW0gKnRoaXMpOwo+ ICsJYm9vbCAoKmlzX2VtcHR5KShzdHJ1Y3Qgc3RyaW5nX3N0cmVhbSAqdGhpcyk7Cj4gK307Cj4g Kwo+ICtzdHJ1Y3Qgc3RyaW5nX3N0cmVhbSAqbmV3X3N0cmluZ19zdHJlYW0odm9pZCk7Cj4gKwo+ ICt2b2lkIGRlc3Ryb3lfc3RyaW5nX3N0cmVhbShzdHJ1Y3Qgc3RyaW5nX3N0cmVhbSAqc3RyZWFt KTsKPiArCj4gK3ZvaWQgc3RyaW5nX3N0cmVhbV9nZXQoc3RydWN0IHN0cmluZ19zdHJlYW0gKnN0 cmVhbSk7Cj4gKwo+ICtpbnQgc3RyaW5nX3N0cmVhbV9wdXQoc3RydWN0IHN0cmluZ19zdHJlYW0g KnN0cmVhbSk7Cj4gKwo+ICsjZW5kaWYgLyogX0tVTklUX1NUUklOR19TVFJFQU1fSCAqLwo+IGRp ZmYgLS1naXQgYS9rdW5pdC9NYWtlZmlsZSBiL2t1bml0L01ha2VmaWxlCj4gaW5kZXggNWVmZGM0 ZGVhMmMwOC4uMjc1YjU2NWEwZTgxZiAxMDA2NDQKPiAtLS0gYS9rdW5pdC9NYWtlZmlsZQo+ICsr KyBiL2t1bml0L01ha2VmaWxlCj4gQEAgLTEgKzEsMiBAQAo+IC1vYmotJChDT05GSUdfS1VOSVQp ICs9CQkJdGVzdC5vCj4gK29iai0kKENPTkZJR19LVU5JVCkgKz0JCQl0ZXN0Lm8gXAo+ICsJCQkJ CXN0cmluZy1zdHJlYW0ubwo+IGRpZmYgLS1naXQgYS9rdW5pdC9zdHJpbmctc3RyZWFtLmMgYi9r dW5pdC9zdHJpbmctc3RyZWFtLmMKPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAw MDAwMDAwMDAuLjFlN2VmYTYzMGNjMzUKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIva3VuaXQvc3Ry aW5nLXN0cmVhbS5jCj4gQEAgLTAsMCArMSwxNDkgQEAKPiArLy8gU1BEWC1MaWNlbnNlLUlkZW50 aWZpZXI6IEdQTC0yLjAKPiArLyoKPiArICogQysrIHN0cmVhbSBzdHlsZSBzdHJpbmcgYnVpbGRl ciB1c2VkIGluIEtVbml0IGZvciBidWlsZGluZyBtZXNzYWdlcy4KPiArICoKPiArICogQ29weXJp Z2h0IChDKSAyMDE4LCBHb29nbGUgTExDLgo+ICsgKiBBdXRob3I6IEJyZW5kYW4gSGlnZ2lucyA8 YnJlbmRhbmhpZ2dpbnNAZ29vZ2xlLmNvbT4KPiArICovCj4gKwo+ICsjaW5jbHVkZSA8bGludXgv bGlzdC5oPgo+ICsjaW5jbHVkZSA8bGludXgvc2xhYi5oPgo+ICsjaW5jbHVkZSA8a3VuaXQvc3Ry aW5nLXN0cmVhbS5oPgo+ICsKPiArc3RhdGljIGludCBzdHJpbmdfc3RyZWFtX3ZhZGQoc3RydWN0 IHN0cmluZ19zdHJlYW0gKnRoaXMsCj4gKwkJCSAgICAgICBjb25zdCBjaGFyICpmbXQsCj4gKwkJ CSAgICAgICB2YV9saXN0IGFyZ3MpCj4gK3sKPiArCXN0cnVjdCBzdHJpbmdfc3RyZWFtX2ZyYWdt ZW50ICpmcmFnbWVudDsKPiArCWludCBsZW47Cj4gKwl2YV9saXN0IGFyZ3NfZm9yX2NvdW50aW5n Owo+ICsJdW5zaWduZWQgbG9uZyBmbGFnczsKPiArCj4gKwkvKiBNYWtlIGEgY29weSBiZWNhdXNl IGB2c25wcmludGZgIGNvdWxkIGNoYW5nZSBpdCAqLwo+ICsJdmFfY29weShhcmdzX2Zvcl9jb3Vu dGluZywgYXJncyk7Cj4gKwo+ICsJLyogTmVlZCBzcGFjZSBmb3IgbnVsbCBieXRlLiAqLwo+ICsJ bGVuID0gdnNucHJpbnRmKE5VTEwsIDAsIGZtdCwgYXJnc19mb3JfY291bnRpbmcpICsgMTsKPiAr Cj4gKwl2YV9lbmQoYXJnc19mb3JfY291bnRpbmcpOwo+ICsKPiArCWZyYWdtZW50ID0ga21hbGxv YyhzaXplb2YoKmZyYWdtZW50KSwgR0ZQX0tFUk5FTCk7Cj4gKwlpZiAoIWZyYWdtZW50KQo+ICsJ CXJldHVybiAtRU5PTUVNOwo+ICsKPiArCWZyYWdtZW50LT5mcmFnbWVudCA9IGttYWxsb2MobGVu LCBHRlBfS0VSTkVMKTsKPiArCWlmICghZnJhZ21lbnQtPmZyYWdtZW50KSB7Cj4gKwkJa2ZyZWUo ZnJhZ21lbnQpOwo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsJfQo+ICsKPiArCWxlbiA9IHZzbnBy aW50ZihmcmFnbWVudC0+ZnJhZ21lbnQsIGxlbiwgZm10LCBhcmdzKTsKPiArCXNwaW5fbG9ja19p cnFzYXZlKCZ0aGlzLT5sb2NrLCBmbGFncyk7Cj4gKwl0aGlzLT5sZW5ndGggKz0gbGVuOwo+ICsJ bGlzdF9hZGRfdGFpbCgmZnJhZ21lbnQtPm5vZGUsICZ0aGlzLT5mcmFnbWVudHMpOwo+ICsJc3Bp bl91bmxvY2tfaXJxcmVzdG9yZSgmdGhpcy0+bG9jaywgZmxhZ3MpOwo+ICsJcmV0dXJuIDA7Cj4g K30KPiArCj4gK3N0YXRpYyBpbnQgc3RyaW5nX3N0cmVhbV9hZGQoc3RydWN0IHN0cmluZ19zdHJl YW0gKnRoaXMsIGNvbnN0IGNoYXIgKmZtdCwgLi4uKQo+ICt7Cj4gKwl2YV9saXN0IGFyZ3M7Cj4g KwlpbnQgcmVzdWx0Owo+ICsKPiArCXZhX3N0YXJ0KGFyZ3MsIGZtdCk7Cj4gKwlyZXN1bHQgPSBz dHJpbmdfc3RyZWFtX3ZhZGQodGhpcywgZm10LCBhcmdzKTsKPiArCXZhX2VuZChhcmdzKTsKPiAr CXJldHVybiByZXN1bHQ7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIHN0cmluZ19zdHJlYW1fY2xl YXIoc3RydWN0IHN0cmluZ19zdHJlYW0gKnRoaXMpCj4gK3sKPiArCXN0cnVjdCBzdHJpbmdfc3Ry ZWFtX2ZyYWdtZW50ICpmcmFnbWVudCwgKmZyYWdtZW50X3NhZmU7Cj4gKwl1bnNpZ25lZCBsb25n IGZsYWdzOwo+ICsKPiArCXNwaW5fbG9ja19pcnFzYXZlKCZ0aGlzLT5sb2NrLCBmbGFncyk7Cj4g KwlsaXN0X2Zvcl9lYWNoX2VudHJ5X3NhZmUoZnJhZ21lbnQsCj4gKwkJCQkgZnJhZ21lbnRfc2Fm ZSwKPiArCQkJCSAmdGhpcy0+ZnJhZ21lbnRzLAo+ICsJCQkJIG5vZGUpIHsKPiArCQlsaXN0X2Rl bCgmZnJhZ21lbnQtPm5vZGUpOwo+ICsJCWtmcmVlKGZyYWdtZW50LT5mcmFnbWVudCk7Cj4gKwkJ a2ZyZWUoZnJhZ21lbnQpOwo+ICsJfQo+ICsJdGhpcy0+bGVuZ3RoID0gMDsKPiArCXNwaW5fdW5s b2NrX2lycXJlc3RvcmUoJnRoaXMtPmxvY2ssIGZsYWdzKTsKPiArfQo+ICsKPiArc3RhdGljIGNo YXIgKnN0cmluZ19zdHJlYW1fZ2V0X3N0cmluZyhzdHJ1Y3Qgc3RyaW5nX3N0cmVhbSAqdGhpcykK PiArewo+ICsJc3RydWN0IHN0cmluZ19zdHJlYW1fZnJhZ21lbnQgKmZyYWdtZW50Owo+ICsJc2l6 ZV90IGJ1Zl9sZW4gPSB0aGlzLT5sZW5ndGggKyAxOyAvKiArMSBmb3IgbnVsbCBieXRlLiAqLwo+ ICsJY2hhciAqYnVmOwo+ICsJdW5zaWduZWQgbG9uZyBmbGFnczsKPiArCj4gKwlidWYgPSBremFs bG9jKGJ1Zl9sZW4sIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFidWYpCj4gKwkJcmV0dXJuIE5VTEw7 Cj4gKwo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJnRoaXMtPmxvY2ssIGZsYWdzKTsKPiArCWxpc3Rf Zm9yX2VhY2hfZW50cnkoZnJhZ21lbnQsICZ0aGlzLT5mcmFnbWVudHMsIG5vZGUpCj4gKwkJc3Ry bGNhdChidWYsIGZyYWdtZW50LT5mcmFnbWVudCwgYnVmX2xlbik7Cj4gKwlzcGluX3VubG9ja19p cnFyZXN0b3JlKCZ0aGlzLT5sb2NrLCBmbGFncyk7Cj4gKwo+ICsJcmV0dXJuIGJ1ZjsKPiArfQo+ ICsKPiArc3RhdGljIGJvb2wgc3RyaW5nX3N0cmVhbV9pc19lbXB0eShzdHJ1Y3Qgc3RyaW5nX3N0 cmVhbSAqdGhpcykKPiArewo+ICsJYm9vbCBpc19lbXB0eTsKPiArCXVuc2lnbmVkIGxvbmcgZmxh Z3M7Cj4gKwo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJnRoaXMtPmxvY2ssIGZsYWdzKTsKPiArCWlz X2VtcHR5ID0gbGlzdF9lbXB0eSgmdGhpcy0+ZnJhZ21lbnRzKTsKPiArCXNwaW5fdW5sb2NrX2ly cXJlc3RvcmUoJnRoaXMtPmxvY2ssIGZsYWdzKTsKPiArCj4gKwlyZXR1cm4gaXNfZW1wdHk7Cj4g K30KPiArCj4gK3ZvaWQgZGVzdHJveV9zdHJpbmdfc3RyZWFtKHN0cnVjdCBzdHJpbmdfc3RyZWFt ICpzdHJlYW0pCj4gK3sKPiArCXN0cmVhbS0+Y2xlYXIoc3RyZWFtKTsKPiArCWtmcmVlKHN0cmVh bSk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIHN0cmluZ19zdHJlYW1fZGVzdHJveShzdHJ1Y3Qg a3JlZiAqa3JlZikKPiArewo+ICsJc3RydWN0IHN0cmluZ19zdHJlYW0gKnN0cmVhbSA9IGNvbnRh aW5lcl9vZihrcmVmLAo+ICsJCQkJCQkgICAgc3RydWN0IHN0cmluZ19zdHJlYW0sCj4gKwkJCQkJ CSAgICByZWZjb3VudCk7Cj4gKwlkZXN0cm95X3N0cmluZ19zdHJlYW0oc3RyZWFtKTsKPiArfQo+ ICsKPiArc3RydWN0IHN0cmluZ19zdHJlYW0gKm5ld19zdHJpbmdfc3RyZWFtKHZvaWQpCj4gK3sK PiArCXN0cnVjdCBzdHJpbmdfc3RyZWFtICpzdHJlYW0gPSBremFsbG9jKHNpemVvZigqc3RyZWFt KSwgR0ZQX0tFUk5FTCk7Cj4gKwo+ICsJaWYgKCFzdHJlYW0pCj4gKwkJcmV0dXJuIE5VTEw7Cj4g Kwo+ICsJSU5JVF9MSVNUX0hFQUQoJnN0cmVhbS0+ZnJhZ21lbnRzKTsKPiArCXNwaW5fbG9ja19p bml0KCZzdHJlYW0tPmxvY2spOwo+ICsJa3JlZl9pbml0KCZzdHJlYW0tPnJlZmNvdW50KTsKPiAr CXN0cmVhbS0+YWRkID0gc3RyaW5nX3N0cmVhbV9hZGQ7Cj4gKwlzdHJlYW0tPnZhZGQgPSBzdHJp bmdfc3RyZWFtX3ZhZGQ7Cj4gKwlzdHJlYW0tPmdldF9zdHJpbmcgPSBzdHJpbmdfc3RyZWFtX2dl dF9zdHJpbmc7Cj4gKwlzdHJlYW0tPmNsZWFyID0gc3RyaW5nX3N0cmVhbV9jbGVhcjsKPiArCXN0 cmVhbS0+aXNfZW1wdHkgPSBzdHJpbmdfc3RyZWFtX2lzX2VtcHR5Owo+ICsJcmV0dXJuIHN0cmVh bTsKPiArfQo+ICsKPiArdm9pZCBzdHJpbmdfc3RyZWFtX2dldChzdHJ1Y3Qgc3RyaW5nX3N0cmVh bSAqc3RyZWFtKQo+ICt7Cj4gKwlrcmVmX2dldCgmc3RyZWFtLT5yZWZjb3VudCk7Cj4gK30KPiAr Cj4gK2ludCBzdHJpbmdfc3RyZWFtX3B1dChzdHJ1Y3Qgc3RyaW5nX3N0cmVhbSAqc3RyZWFtKQo+ ICt7Cj4gKwlyZXR1cm4ga3JlZl9wdXQoJnN0cmVhbS0+cmVmY291bnQsICZzdHJpbmdfc3RyZWFt X2Rlc3Ryb3kpOwo+ICt9Cj4gKwo+IC0tIAo+IDIuMjAuMC5yYzAuMzg3LmdjN2E2OWU2YjZjLWdv b2cKPiAKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KZHJp LWRldmVsIG1haWxpbmcgbGlzdApkcmktZGV2ZWxAbGlzdHMuZnJlZWRlc2t0b3Aub3JnCmh0dHBz Oi8vbGlzdHMuZnJlZWRlc2t0b3Aub3JnL21haWxtYW4vbGlzdGluZm8vZHJpLWRldmVsCg== From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pg1-f195.google.com ([209.85.215.195]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1gSZUp-00086z-QD for linux-um@lists.infradead.org; Fri, 30 Nov 2018 03:29:41 +0000 Received: by mail-pg1-f195.google.com with SMTP id 70so1870548pgh.8 for ; Thu, 29 Nov 2018 19:29:29 -0800 (PST) Date: Thu, 29 Nov 2018 19:29:24 -0800 From: Luis Chamberlain Subject: Re: [RFC v3 03/19] kunit: test: add string_stream a std::stream like string builder Message-ID: <20181130032924.GH18410@garbanzo.do-not-panic.com> References: <20181128193636.254378-1-brendanhiggins@google.com> <20181128193636.254378-4-brendanhiggins@google.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20181128193636.254378-4-brendanhiggins@google.com> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-um" Errors-To: linux-um-bounces+geert=linux-m68k.org@lists.infradead.org To: Brendan Higgins , Petr Mladek Cc: brakmo@fb.com, dri-devel@lists.freedesktop.org, linux-kselftest@vger.kernel.org, shuah@kernel.org, robh@kernel.org, frowand.list@gmail.com, linux-nvdimm@lists.01.org, richard@nod.at, knut.omang@oracle.com, kieran.bingham@ideasonboard.com, joel@jms.id.au, jdike@addtoit.com, Tim.Bird@sony.com, keescook@google.com, linux-um@lists.infradead.org, rostedt@goodmis.org, julia.lawall@lip6.fr, dan.j.williams@intel.com, kunit-dev@googlegroups.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, daniel@ffwll.ch, mpe@ellerman.id.au, joe@perches.com, khilman@baylibre.com On Wed, Nov 28, 2018 at 11:36:20AM -0800, Brendan Higgins wrote: > A number of test features need to do pretty complicated string printing > where it may not be possible to rely on a single preallocated string > with parameters. > > So provide a library for constructing the string as you go similar to > C++'s std::string. Hrm, what's the potential for such thing actually being eventually generically useful for printk folks, I wonder? Petr? Luis > > Signed-off-by: Brendan Higgins > --- > include/kunit/string-stream.h | 44 ++++++++++ > kunit/Makefile | 3 +- > kunit/string-stream.c | 149 ++++++++++++++++++++++++++++++++++ > 3 files changed, 195 insertions(+), 1 deletion(-) > create mode 100644 include/kunit/string-stream.h > create mode 100644 kunit/string-stream.c > > diff --git a/include/kunit/string-stream.h b/include/kunit/string-stream.h > new file mode 100644 > index 0000000000000..933ed5740cf07 > --- /dev/null > +++ b/include/kunit/string-stream.h > @@ -0,0 +1,44 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#ifndef _KUNIT_STRING_STREAM_H > +#define _KUNIT_STRING_STREAM_H > + > +#include > +#include > +#include > +#include > + > +struct string_stream_fragment { > + struct list_head node; > + char *fragment; > +}; > + > +struct string_stream { > + size_t length; > + struct list_head fragments; > + > + /* length and fragments are protected by this lock */ > + spinlock_t lock; > + struct kref refcount; > + int (*add)(struct string_stream *this, const char *fmt, ...); > + int (*vadd)(struct string_stream *this, const char *fmt, va_list args); > + char *(*get_string)(struct string_stream *this); > + void (*clear)(struct string_stream *this); > + bool (*is_empty)(struct string_stream *this); > +}; > + > +struct string_stream *new_string_stream(void); > + > +void destroy_string_stream(struct string_stream *stream); > + > +void string_stream_get(struct string_stream *stream); > + > +int string_stream_put(struct string_stream *stream); > + > +#endif /* _KUNIT_STRING_STREAM_H */ > diff --git a/kunit/Makefile b/kunit/Makefile > index 5efdc4dea2c08..275b565a0e81f 100644 > --- a/kunit/Makefile > +++ b/kunit/Makefile > @@ -1 +1,2 @@ > -obj-$(CONFIG_KUNIT) += test.o > +obj-$(CONFIG_KUNIT) += test.o \ > + string-stream.o > diff --git a/kunit/string-stream.c b/kunit/string-stream.c > new file mode 100644 > index 0000000000000..1e7efa630cc35 > --- /dev/null > +++ b/kunit/string-stream.c > @@ -0,0 +1,149 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * C++ stream style string builder used in KUnit for building messages. > + * > + * Copyright (C) 2018, Google LLC. > + * Author: Brendan Higgins > + */ > + > +#include > +#include > +#include > + > +static int string_stream_vadd(struct string_stream *this, > + const char *fmt, > + va_list args) > +{ > + struct string_stream_fragment *fragment; > + int len; > + va_list args_for_counting; > + unsigned long flags; > + > + /* Make a copy because `vsnprintf` could change it */ > + va_copy(args_for_counting, args); > + > + /* Need space for null byte. */ > + len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1; > + > + va_end(args_for_counting); > + > + fragment = kmalloc(sizeof(*fragment), GFP_KERNEL); > + if (!fragment) > + return -ENOMEM; > + > + fragment->fragment = kmalloc(len, GFP_KERNEL); > + if (!fragment->fragment) { > + kfree(fragment); > + return -ENOMEM; > + } > + > + len = vsnprintf(fragment->fragment, len, fmt, args); > + spin_lock_irqsave(&this->lock, flags); > + this->length += len; > + list_add_tail(&fragment->node, &this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + return 0; > +} > + > +static int string_stream_add(struct string_stream *this, const char *fmt, ...) > +{ > + va_list args; > + int result; > + > + va_start(args, fmt); > + result = string_stream_vadd(this, fmt, args); > + va_end(args); > + return result; > +} > + > +static void string_stream_clear(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment, *fragment_safe; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry_safe(fragment, > + fragment_safe, > + &this->fragments, > + node) { > + list_del(&fragment->node); > + kfree(fragment->fragment); > + kfree(fragment); > + } > + this->length = 0; > + spin_unlock_irqrestore(&this->lock, flags); > +} > + > +static char *string_stream_get_string(struct string_stream *this) > +{ > + struct string_stream_fragment *fragment; > + size_t buf_len = this->length + 1; /* +1 for null byte. */ > + char *buf; > + unsigned long flags; > + > + buf = kzalloc(buf_len, GFP_KERNEL); > + if (!buf) > + return NULL; > + > + spin_lock_irqsave(&this->lock, flags); > + list_for_each_entry(fragment, &this->fragments, node) > + strlcat(buf, fragment->fragment, buf_len); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return buf; > +} > + > +static bool string_stream_is_empty(struct string_stream *this) > +{ > + bool is_empty; > + unsigned long flags; > + > + spin_lock_irqsave(&this->lock, flags); > + is_empty = list_empty(&this->fragments); > + spin_unlock_irqrestore(&this->lock, flags); > + > + return is_empty; > +} > + > +void destroy_string_stream(struct string_stream *stream) > +{ > + stream->clear(stream); > + kfree(stream); > +} > + > +static void string_stream_destroy(struct kref *kref) > +{ > + struct string_stream *stream = container_of(kref, > + struct string_stream, > + refcount); > + destroy_string_stream(stream); > +} > + > +struct string_stream *new_string_stream(void) > +{ > + struct string_stream *stream = kzalloc(sizeof(*stream), GFP_KERNEL); > + > + if (!stream) > + return NULL; > + > + INIT_LIST_HEAD(&stream->fragments); > + spin_lock_init(&stream->lock); > + kref_init(&stream->refcount); > + stream->add = string_stream_add; > + stream->vadd = string_stream_vadd; > + stream->get_string = string_stream_get_string; > + stream->clear = string_stream_clear; > + stream->is_empty = string_stream_is_empty; > + return stream; > +} > + > +void string_stream_get(struct string_stream *stream) > +{ > + kref_get(&stream->refcount); > +} > + > +int string_stream_put(struct string_stream *stream) > +{ > + return kref_put(&stream->refcount, &string_stream_destroy); > +} > + > -- > 2.20.0.rc0.387.gc7a69e6b6c-goog > _______________________________________________ linux-um mailing list linux-um@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-um