diff --git a/include/nuttx/streams.h b/include/nuttx/streams.h index c49f6f0718..6ba76492b9 100644 --- a/include/nuttx/streams.h +++ b/include/nuttx/streams.h @@ -217,6 +217,14 @@ struct lib_rawsostream_s int fd; }; +struct lib_bufferedoutstream_s +{ + struct lib_outstream_s public; + FAR struct lib_outstream_s *backend; + int pending; + char buffer[CONFIG_STREAM_OUT_BUFFER_SIZE]; +}; + /* This is a special stream that does buffered character I/O. NOTE that is * CONFIG_SYSLOG_BUFFER is not defined, it is the same as struct * lib_outstream_s @@ -372,6 +380,26 @@ void lib_rawoutstream(FAR struct lib_rawoutstream_s *outstream, int fd); void lib_rawsistream(FAR struct lib_rawsistream_s *instream, int fd); void lib_rawsostream(FAR struct lib_rawsostream_s *outstream, int fd); +/**************************************************************************** + * Name: lib_bufferedoutstream + * + * Description: + * Wrap a raw output stream to a buffered output stream. + * + * Input Parameters: + * outstream - User allocated, uninitialized instance of struct + * lib_bufferedoutstream_s to be initialized. + * backend - User allocated, initialized instance of struct + * lib_outstream_s to be buffered. + * + * Returned Value: + * None (User allocated instance initialized). + * + ****************************************************************************/ + +void lib_bufferedoutstream(FAR struct lib_bufferedoutstream_s *outstream, + FAR struct lib_outstream_s *backend); + /**************************************************************************** * Name: lib_lowoutstream * diff --git a/libs/libc/stdio/lib_vdprintf.c b/libs/libc/stdio/lib_vdprintf.c index 90a4b2367c..27d94df583 100644 --- a/libs/libc/stdio/lib_vdprintf.c +++ b/libs/libc/stdio/lib_vdprintf.c @@ -50,10 +50,15 @@ int vdprintf(int fd, FAR const IPTR char *fmt, va_list ap) { + int ret; struct lib_rawoutstream_s rawoutstream; + struct lib_bufferedoutstream_s outstream; /* Wrap the fd in a stream object and let lib_vsprintf do the work. */ lib_rawoutstream(&rawoutstream, fd); - return lib_vsprintf(&rawoutstream.public, fmt, ap); + lib_bufferedoutstream(&outstream, &rawoutstream.public); + ret = lib_vsprintf(&outstream.public, fmt, ap); + lib_stream_flush(&outstream.public); + return ret; } diff --git a/libs/libc/stream/Kconfig b/libs/libc/stream/Kconfig index 90554aa661..77cb42e3da 100644 --- a/libs/libc/stream/Kconfig +++ b/libs/libc/stream/Kconfig @@ -21,4 +21,8 @@ config STREAM_LZF_BLOG endif +config STREAM_OUT_BUFFER_SIZE + int "Output stream buffer size" + default 64 + endmenu # Locale Support diff --git a/libs/libc/stream/Make.defs b/libs/libc/stream/Make.defs index 868ff05576..0b6757c9bd 100644 --- a/libs/libc/stream/Make.defs +++ b/libs/libc/stream/Make.defs @@ -26,7 +26,7 @@ CSRCS += lib_memsostream.c lib_lowoutstream.c lib_rawinstream.c CSRCS += lib_rawoutstream.c lib_rawsistream.c lib_rawsostream.c CSRCS += lib_zeroinstream.c lib_nullinstream.c lib_nulloutstream.c CSRCS += lib_mtdoutstream.c lib_libnoflush.c lib_libsnoflush.c -CSRCS += lib_syslogstream.c +CSRCS += lib_syslogstream.c lib_bufferedoutstream.c # The remaining sources files depend upon C streams diff --git a/libs/libc/stream/lib_bufferedoutstream.c b/libs/libc/stream/lib_bufferedoutstream.c new file mode 100644 index 0000000000..4018b0cebb --- /dev/null +++ b/libs/libc/stream/lib_bufferedoutstream.c @@ -0,0 +1,120 @@ +/**************************************************************************** + * libs/libc/stream/lib_bufferedoutstream.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "libc.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bufferedoutstream_flush + ****************************************************************************/ + +static int bufferedoutstream_flush(FAR struct lib_outstream_s *this) +{ + FAR struct lib_bufferedoutstream_s *rthis = + (FAR struct lib_bufferedoutstream_s *)this; + int ret = OK; + + ret = lib_stream_puts(rthis->backend, rthis->buffer, + rthis->pending); + + if (ret >= 0) + { + rthis->pending = 0; + } + + return ret; +} + +/**************************************************************************** + * Name: bufferedoutstream_puts + ****************************************************************************/ + +static int bufferedoutstream_puts(FAR struct lib_outstream_s *this, + FAR const void *buf, int len) +{ + FAR struct lib_bufferedoutstream_s *rthis = + (FAR struct lib_bufferedoutstream_s *)this; + int ret = len; + + if (rthis->pending + len <= CONFIG_STREAM_OUT_BUFFER_SIZE) + { + /* If buffer is enough to save incoming data, cache it */ + + memcpy(rthis->buffer + rthis->pending, buf, len); + rthis->pending += len; + } + else + { + /* Or, for long data flush buffer and write it directly */ + + ret = lib_stream_flush(this); + if (ret >= 0) + { + ret = lib_stream_puts(rthis->backend, buf, len); + } + } + + return ret; +} + +/**************************************************************************** + * Name: bufferedoutstream_putc + ****************************************************************************/ + +static void bufferedoutstream_putc(FAR struct lib_outstream_s *this, int ch) +{ + char c = ch; + + bufferedoutstream_puts(this, &c, 1); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lib_bufferedoutstream + ****************************************************************************/ + +void lib_bufferedoutstream(FAR struct lib_bufferedoutstream_s *outstream, + FAR struct lib_outstream_s *backend) +{ + outstream->public.putc = bufferedoutstream_putc; + outstream->public.puts = bufferedoutstream_puts; + outstream->public.flush = bufferedoutstream_flush; + outstream->public.nput = 0; + outstream->backend = backend; + outstream->pending = 0; +}