Syslog buffering: Use IOBs to buffer data, not an on-stack buffer

This commit is contained in:
Gregory Nutt
2017-05-10 17:36:08 -06:00
parent d8a83f16be
commit d3b9f5b37f
7 changed files with 171 additions and 70 deletions
+2 -1
View File
@@ -51,6 +51,7 @@
#include <nuttx/irq.h> #include <nuttx/irq.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/semaphore.h> #include <nuttx/semaphore.h>
#include <nuttx/fs/fs.h> #include <nuttx/fs/fs.h>
#include <nuttx/serial/serial.h> #include <nuttx/serial/serial.h>
@@ -365,7 +366,7 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer,
* a little differently. * a little differently.
*/ */
if (up_interrupt_context() || getpid() == 0) if (up_interrupt_context() || sched_idletask())
{ {
#ifdef CONFIG_SERIAL_REMOVABLE #ifdef CONFIG_SERIAL_REMOVABLE
/* If the removable device is no longer connected, refuse to write to /* If the removable device is no longer connected, refuse to write to
+2 -12
View File
@@ -86,26 +86,16 @@ config SYSLOG_BUFFER
bool "Use buffered output" bool "Use buffered output"
default n default n
depends on SYSLOG_WRITE depends on SYSLOG_WRITE
select MM_IOB
---help--- ---help---
Enables an buffering logic that will be used to serialize debug Enables an buffering logic that will be used to serialize debug
output from concurrent tasks. This enables allocation of one buffer output from concurrent tasks. This enables allocation of one buffer
per thread, each of size CONFIG_SYSLOG_BUFSIZE. per thread, each of size CONFIG_IOB_BUFSIZE.
The use of SYSLOG buffering is optional. If not enabled, however, The use of SYSLOG buffering is optional. If not enabled, however,
then the output from multiple tasks that attempt to generate SYSLOG then the output from multiple tasks that attempt to generate SYSLOG
output may be interleaved and difficult to read. output may be interleaved and difficult to read.
config SYSLOG_BUFSIZE
int "Output buffer size"
default 32
range 1 65535
depends on SYSLOG_BUFFER
---help---
If CONFIG_SYSLOG_BUFFER is enabled, then CONFIG_SYSLOG_BUFSIZE
provides the size of the per-thread output buffer. Setting
CONFIG_SYSLOG_BUFSIZE to a value less than one effectly disables
output SYSLOG buffering.
config SYSLOG_INTBUFFER config SYSLOG_INTBUFFER
bool "Use interrupt buffer" bool "Use interrupt buffer"
default n default n
+117 -47
View File
@@ -44,8 +44,9 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <nuttx/syslog/syslog.h>
#include <nuttx/streams.h> #include <nuttx/streams.h>
#include <nuttx/mm/iob.h>
#include <nuttx/syslog/syslog.h>
#include "syslog.h" #include "syslog.h"
@@ -59,55 +60,67 @@
static void syslogstream_putc(FAR struct lib_outstream_s *this, int ch) static void syslogstream_putc(FAR struct lib_outstream_s *this, int ch)
{ {
#ifdef CONFIG_SYSLOG_BUFFER
FAR struct lib_syslogstream_s *stream = (FAR struct lib_syslogstream_s *)this;
/* Discard carriage returns */ /* Discard carriage returns */
if (ch != '\r') if (ch != '\r')
{ {
/* Add the incoming character to the buffer */ #ifdef CONFIG_SYSLOG_BUFFER
FAR struct lib_syslogstream_s *stream;
FAR struct iob_s *iob;
stream->buf[stream->nbuf] = ch; DEBUGASSERT(this != NULL);
stream->nbuf++; stream = (FAR struct lib_syslogstream_s *)this;
this->nput++; iob = stream->iob;
/* Is the buffer full? Did we encounter a new line? */ /* Do we have an IO buffer? */
if (stream->nbuf >= CONFIG_SYSLOG_BUFSIZE || ch == '\n') if (iob != NULL)
{ {
/* Yes.. then flush the buffer */ /* Yes.. Add the incoming character to the buffer */
(void)this->flush(this); iob->io_data[iob->io_len] = ch;
} iob->io_len++;
}
#else
int ret;
/* Try writing until the write was successful or until an irrecoverable
* error occurs.
*/
do
{
/* Write the character to the supported logging device. On failure,
* syslog_putc returns EOF with the errno value set;
*/
ret = syslog_putc(ch);
if (ret != EOF)
{
this->nput++; this->nput++;
return;
}
/* The special errno value -EINTR means that syslog_putc() was /* Is the buffer full? Did we encounter a new line? */
* awakened by a signal. This is not a real error and must be
* ignored in this context. if (iob->io_len >= CONFIG_IOB_BUFSIZE || ch == '\n')
*/ {
} /* Yes.. then flush the buffer */
while (get_errno() == -EINTR);
(void)this->flush(this);
}
}
else
#endif #endif
{
int ret;
/* Try writing until the write was successful or until an
* irrecoverable error occurs.
*/
do
{
/* Write the character to the supported logging device. On
* failure, syslog_putc returns EOF with the errno value set;
*/
ret = syslog_putc(ch);
if (ret != EOF)
{
this->nput++;
return;
}
/* The special errno value -EINTR means that syslog_putc() was
* awakened by a signal. This is not a real error and must be
* ignored in this context.
*/
}
while (get_errno() == -EINTR);
}
}
} }
/**************************************************************************** /****************************************************************************
@@ -117,25 +130,31 @@ static void syslogstream_putc(FAR struct lib_outstream_s *this, int ch)
#ifdef CONFIG_SYSLOG_BUFFER #ifdef CONFIG_SYSLOG_BUFFER
static int syslogstream_flush(FAR struct lib_outstream_s *this) static int syslogstream_flush(FAR struct lib_outstream_s *this)
{ {
FAR struct lib_syslogstream_s *stream = (FAR struct lib_syslogstream_s *)this; FAR struct lib_syslogstream_s *stream;
FAR struct iob_s *iob;
int ret = OK; int ret = OK;
/* Is there anything buffered? */ DEBUGASSERT(this != NULL);
stream = (FAR struct lib_syslogstream_s *)this;
iob = stream->iob;
if (stream->nbuf > 0) /* Do we have an IO buffer? Is there anything buffered? */
if (iob != NULL && iob->io_len > 0)
{ {
/* Yes write the buffered data */ /* Yes write the buffered data */
do do
{ {
ssize_t nbytes = syslog_write(stream->buf, stream->nbuf); ssize_t nbytes = syslog_write((FAR const char *)iob->io_data,
(size_t)iob->io_len);
if (nbytes < 0) if (nbytes < 0)
{ {
ret = -get_errno(); ret = -get_errno();
} }
else else
{ {
stream->nbuf = 0; iob->io_len = 0;
ret = OK; ret = OK;
} }
} }
@@ -151,7 +170,7 @@ static int syslogstream_flush(FAR struct lib_outstream_s *this)
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: syslogstream * Name: syslogstream_create
* *
* Description: * Description:
* Initializes a stream for use with the configured syslog interface. * Initializes a stream for use with the configured syslog interface.
@@ -159,23 +178,74 @@ static int syslogstream_flush(FAR struct lib_outstream_s *this)
* *
* Input parameters: * Input parameters:
* stream - User allocated, uninitialized instance of struct * stream - User allocated, uninitialized instance of struct
* lib_syslogstream_s to be initialized. * lib_lowoutstream_s to be initialized.
* *
* Returned Value: * Returned Value:
* None (User allocated instance initialized). * None (User allocated instance initialized).
* *
****************************************************************************/ ****************************************************************************/
void syslogstream(FAR struct lib_syslogstream_s *stream) void syslogstream_create(FAR struct lib_syslogstream_s *stream)
{ {
DEBUGASSERT(stream != NULL);
#ifdef CONFIG_SYSLOG_BUFFER #ifdef CONFIG_SYSLOG_BUFFER
FAR struct iob_s *iob;
/* Initialize the common fields */
stream->public.put = syslogstream_putc; stream->public.put = syslogstream_putc;
stream->public.flush = syslogstream_flush; stream->public.flush = syslogstream_flush;
stream->public.nput = 0; stream->public.nput = 0;
stream->nbuf = 0;
/* Allocate an IOB */
iob = iob_alloc(true);
stream->iob = iob;
if (iob != NULL)
{
/* Initialize the IOB */
iob->io_len = 0;
iob->io_offset = 0;
iob->io_pktlen = 0;
}
#else #else
stream->public.put = syslogstream_putc; stream->public.put = syslogstream_putc;
stream->public.flush = lib_noflush; stream->public.flush = lib_noflush;
stream->public.nput = 0; stream->public.nput = 0;
#endif #endif
} }
/****************************************************************************
* Name: syslogstream_destroy
*
* Description:
* Free resources held by the syslog stream.
*
* Input parameters:
* stream - User allocated, uninitialized instance of struct
* lib_lowoutstream_s to be initialized.
*
* Returned Value:
* None (Resources freed).
*
****************************************************************************/
#ifdef CONFIG_SYSLOG_BUFFER
void syslogstream_destroy(FAR struct lib_syslogstream_s *stream)
{
DEBUGASSERT(stream != NULL);
/* Verify that there is an IOB attached (there should be) */
if (stream->iob != NULL)
{
/* Free the IOB */
iob_free(stream->iob);
stream->iob = NULL;
}
}
#endif
+18 -3
View File
@@ -68,15 +68,17 @@
int _vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap) int _vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap)
{ {
struct lib_syslogstream_s stream; struct lib_syslogstream_s stream;
int ret;
#ifdef CONFIG_SYSLOG_TIMESTAMP #ifdef CONFIG_SYSLOG_TIMESTAMP
struct timespec ts; struct timespec ts;
int ret = -1;
/* Get the current time. Since debug output may be generated very early /* Get the current time. Since debug output may be generated very early
* in the start-up sequence, hardware timer support may not yet be * in the start-up sequence, hardware timer support may not yet be
* available. * available.
*/ */
ret = -EAGAIN;
if (OSINIT_HW_READY()) if (OSINIT_HW_READY())
{ {
/* Prefer monotonic when enabled, as it can be synchronized to /* Prefer monotonic when enabled, as it can be synchronized to
@@ -114,7 +116,7 @@ int _vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap)
{ {
/* Use the normal SYSLOG stream */ /* Use the normal SYSLOG stream */
syslogstream(&stream); syslogstream_create(&stream);
} }
#if defined(CONFIG_SYSLOG_TIMESTAMP) #if defined(CONFIG_SYSLOG_TIMESTAMP)
@@ -124,5 +126,18 @@ int _vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap)
ts.tv_sec, ts.tv_nsec/1000); ts.tv_sec, ts.tv_nsec/1000);
#endif #endif
return lib_vsprintf(&stream.public, fmt, *ap); /* Generate the output */
ret = lib_vsprintf(&stream.public, fmt, *ap);
#ifdef CONFIG_SYSLOG_BUFFER
/* Destroy the syslog stream buffer */
if (priority != LOG_EMERG)
{
syslogstream_destroy(&stream);
}
#endif
return ret;
} }
+1 -1
View File
@@ -760,7 +760,7 @@ FAR struct tcb_s *sched_self(void);
void sched_foreach(sched_foreach_t handler, FAR void *arg); void sched_foreach(sched_foreach_t handler, FAR void *arg);
/* Give a task ID, look up the corresponding TCB */ /* Given a task ID, look up the corresponding TCB */
FAR struct tcb_s *sched_gettcb(pid_t pid); FAR struct tcb_s *sched_gettcb(pid_t pid);
+29 -5
View File
@@ -190,14 +190,17 @@ struct lib_rawsostream_s
}; };
/* This is a special stream that does buffered character I/O. NOTE that is /* 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 */ * CONFIG_SYSLOG_BUFFER is not defined, it is the same as struct
* lib_outstream_s
*/
struct iob_s; /* Forward reference */
struct lib_syslogstream_s struct lib_syslogstream_s
{ {
struct lib_outstream_s public; struct lib_outstream_s public;
#ifdef CONFIG_SYSLOG_BUFFER #ifdef CONFIG_SYSLOG_BUFFER
unsigned int nbuf; FAR struct iob_s *iob;
char buf[CONFIG_SYSLOG_BUFSIZE];
#endif #endif
}; };
@@ -357,7 +360,7 @@ void lib_nullinstream(FAR struct lib_instream_s *nullinstream);
void lib_nulloutstream(FAR struct lib_outstream_s *nulloutstream); void lib_nulloutstream(FAR struct lib_outstream_s *nulloutstream);
/**************************************************************************** /****************************************************************************
* Name: syslogstream * Name: syslogstream_create
* *
* Description: * Description:
* Initializes a stream for use with the configured syslog interface. * Initializes a stream for use with the configured syslog interface.
@@ -372,7 +375,28 @@ void lib_nulloutstream(FAR struct lib_outstream_s *nulloutstream);
* *
****************************************************************************/ ****************************************************************************/
void syslogstream(FAR struct lib_syslogstream_s *stream); void syslogstream_create(FAR struct lib_syslogstream_s *stream);
/****************************************************************************
* Name: syslogstream_destroy
*
* Description:
* Free resources held by the syslog stream.
*
* Input parameters:
* stream - User allocated, uninitialized instance of struct
* lib_lowoutstream_s to be initialized.
*
* Returned Value:
* None (Resources freed).
*
****************************************************************************/
#ifdef CONFIG_SYSLOG_BUFFER
void syslogstream_destroy(FAR struct lib_syslogstream_s *stream);
#else
# define syslogstream_destroy(s)
#endif
/**************************************************************************** /****************************************************************************
* Name: emergstream * Name: emergstream
+2 -1
View File
@@ -45,6 +45,7 @@
#include <nuttx/irq.h> #include <nuttx/irq.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/mm/iob.h> #include <nuttx/mm/iob.h>
#include "iob.h" #include "iob.h"
@@ -172,7 +173,7 @@ FAR struct iob_s *iob_alloc(bool throttled)
{ {
/* Were we called from the interrupt level? */ /* Were we called from the interrupt level? */
if (up_interrupt_context()) if (up_interrupt_context() || sched_idletask())
{ {
/* Yes, then try to allocate an I/O buffer without waiting */ /* Yes, then try to allocate an I/O buffer without waiting */