mirror of
https://github.com/apache/nuttx.git
synced 2026-05-27 19:36:35 +08:00
SYSLOG: Flesh out interrupt buffer logic
This commit is contained in:
@@ -524,7 +524,4 @@ menuconfig DRIVERS_WIRELESS
|
|||||||
Drivers for various wireless devices.
|
Drivers for various wireless devices.
|
||||||
|
|
||||||
source drivers/wireless/Kconfig
|
source drivers/wireless/Kconfig
|
||||||
|
|
||||||
comment "System Logging Device Options"
|
|
||||||
|
|
||||||
source drivers/syslog/Kconfig
|
source drivers/syslog/Kconfig
|
||||||
|
|||||||
+15
-1
@@ -5,6 +5,20 @@
|
|||||||
|
|
||||||
comment "System Logging"
|
comment "System Logging"
|
||||||
|
|
||||||
|
config SYSLOG_INTBUFFER
|
||||||
|
bool "Use interrupt buffer"
|
||||||
|
default n
|
||||||
|
---help---
|
||||||
|
Enables an interrupt buffer that will be used to serialize debug
|
||||||
|
output from interrupt handlers.
|
||||||
|
|
||||||
|
config SYSLOG_INTBUFSIZE
|
||||||
|
int "Interrupt buffer size"
|
||||||
|
default 2048
|
||||||
|
depends on SYSLOG_INTBUFFER
|
||||||
|
---help---
|
||||||
|
The size of the interrupt buffer in bytes.
|
||||||
|
|
||||||
config RAMLOG
|
config RAMLOG
|
||||||
bool "RAM log device support"
|
bool "RAM log device support"
|
||||||
default n
|
default n
|
||||||
@@ -77,7 +91,7 @@ config SYSLOG_CONSOLE
|
|||||||
default n
|
default n
|
||||||
depends on DEV_CONSOLE
|
depends on DEV_CONSOLE
|
||||||
---help---
|
---help---
|
||||||
Use the syslog logging device as a system console. If this feature is enabled
|
Use the syslog logging device as a system console. If this feature is enabled
|
||||||
(along with DEV_CONSOLE), then all console output will be re-directed to syslog
|
(along with DEV_CONSOLE), then all console output will be re-directed to syslog
|
||||||
output (syslog_putc). This is useful, for example, if the only console is a Telnet
|
output (syslog_putc). This is useful, for example, if the only console is a Telnet
|
||||||
console. Then in that case, console output from non-Telnet threads will go to
|
console. Then in that case, console output from non-Telnet threads will go to
|
||||||
|
|||||||
@@ -42,6 +42,8 @@
|
|||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
@@ -73,12 +73,14 @@ static int syslog_default_flush(void)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SYSLOG_INTBUFFER
|
||||||
static int syslog_force(int ch)
|
static int syslog_force(int ch)
|
||||||
{
|
{
|
||||||
DEBUGASSERT(g_syslog_channel != NULL && g_syslog_channel->sc_force != NULL);
|
DEBUGASSERT(g_syslog_channel != NULL && g_syslog_channel->sc_force != NULL);
|
||||||
|
|
||||||
return g_syslog_channel->sc_force(ch);
|
return g_syslog_channel->sc_force(ch);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
@@ -163,7 +165,7 @@ int syslog_putc(int ch)
|
|||||||
* buffer.
|
* buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(void)syslog_flush_intbuffer(&g_syslog_channel, false);
|
(void)syslog_flush_intbuffer(g_syslog_channel, false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return g_syslog_channel->sc_putc(ch);
|
return g_syslog_channel->sc_putc(ch);
|
||||||
@@ -198,7 +200,7 @@ int syslog_flush(void)
|
|||||||
* buffer.
|
* buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(void)syslog_flush_intbuffer(&g_syslog_channel, true);
|
(void)syslog_flush_intbuffer(g_syslog_channel, true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Then flush all of the buffered output to the SYSLOG device */
|
/* Then flush all of the buffered output to the SYSLOG device */
|
||||||
|
|||||||
@@ -38,9 +38,13 @@
|
|||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include <nuttx/syslog/syslog.h>
|
#include <nuttx/syslog/syslog.h>
|
||||||
|
#include <nuttx/irq.h>
|
||||||
|
|
||||||
#include "syslog.h"
|
#include "syslog.h"
|
||||||
|
|
||||||
@@ -50,10 +54,122 @@
|
|||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Extend the size of the interrupt buffer so that a "[truncated]\n"
|
||||||
|
* indication can be append to the end.
|
||||||
|
*
|
||||||
|
* The usable capacity of the interrupt buffer is (CONFIG_SYSLOG_INTBUFSIZE - 1).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SYSLOG_BUFOVERRUN_MESSAGE "[truncated]\n"
|
||||||
|
#define SYSLOG_BUFOVERRUN_SIZE 13
|
||||||
|
|
||||||
|
#if CONFIG_SYSLOG_INTBUFSIZE > (65535 - SYSLOG_BUFOVERRUN_SIZE)
|
||||||
|
# undef CONFIG_SYSLOG_INTBUFSIZE
|
||||||
|
# define CONFIG_SYSLOG_INTBUFSIZE (65535 - SYSLOG_BUFOVERRUN_SIZE)
|
||||||
|
# define SYSLOG_INTBUFSIZE 65535
|
||||||
|
#else
|
||||||
|
# define SYSLOG_INTBUFSIZE \
|
||||||
|
(CONFIG_SYSLOG_INTBUFSIZE + SYSLOG_BUFOVERRUN_SIZE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define USABLE_INTBUFSIZE (CONFIG_SYSLOG_INTBUFSIZE - 1)
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* This structure encapsulates the interrupt buffer state */
|
||||||
|
|
||||||
|
struct g_syslog_intbuffer_s
|
||||||
|
{
|
||||||
|
volatile uint16_t si_inndx;
|
||||||
|
volatile uint16_t si_outndx;
|
||||||
|
uint8_t si_buffer[SYSLOG_INTBUFSIZE];
|
||||||
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
static struct g_syslog_intbuffer_s g_syslog_intbuffer;
|
||||||
|
static const char g_overrun_msg[SYSLOG_BUFOVERRUN_SIZE] = SYSLOG_BUFOVERRUN_MESSAGE;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: syslog_remove_intbuffer
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Extract any characters that may have been added to the interrupt buffer
|
||||||
|
* to the SYSLOG device.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* On success, the extracted character is returned. EOF is returned if
|
||||||
|
* the interrupt buffer is empty.
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Interrupts may or may not be disabled.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int syslog_remove_intbuffer(void)
|
||||||
|
{
|
||||||
|
irqstate_t flags;
|
||||||
|
uint32_t inndx;
|
||||||
|
uint32_t outndx;
|
||||||
|
uint32_t endndx;
|
||||||
|
int inuse = 0;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
/* Extraction of the character and adjustment of the circular buffer
|
||||||
|
* indices must be performed in a critical section to protect from
|
||||||
|
* concurrent modification from interrupt handlers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
|
||||||
|
/* How much space is left in the inbuffer? */
|
||||||
|
|
||||||
|
inndx = (uint32_t)g_syslog_intbuffer.si_inndx;
|
||||||
|
outndx = (uint32_t)g_syslog_intbuffer.si_outndx;
|
||||||
|
if (inndx != outndx)
|
||||||
|
{
|
||||||
|
/* Handle the case where the endndx has wrapped around */
|
||||||
|
|
||||||
|
endndx = outndx;
|
||||||
|
if (endndx < outndx)
|
||||||
|
{
|
||||||
|
endndx += SYSLOG_INTBUFSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inuse = (int)(endndx - outndx);
|
||||||
|
|
||||||
|
/* Take the next character from the interrupt buffer */
|
||||||
|
|
||||||
|
ch = g_syslog_intbuffer.si_buffer[outndx];
|
||||||
|
|
||||||
|
/* Increment the OUT index, handling wrap-around */
|
||||||
|
|
||||||
|
if (++outndx >= SYSLOG_INTBUFSIZE)
|
||||||
|
{
|
||||||
|
outndx -= SYSLOG_INTBUFSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_syslog_intbuffer.si_outndx = (uint16_t)outndx;
|
||||||
|
}
|
||||||
|
|
||||||
|
leave_critical_section(flags);
|
||||||
|
|
||||||
|
/* Now we can send the extracted character to the SYSLOG device */
|
||||||
|
|
||||||
|
return (inuse > 0) ? ch : EOF;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -74,16 +190,88 @@
|
|||||||
* errno value is returned on any failure.
|
* errno value is returned on any failure.
|
||||||
*
|
*
|
||||||
* Assumptions:
|
* Assumptions:
|
||||||
* Called only from interrupt handling logic; Interrupts will be disabled.
|
* - Called only from interrupt handling logic; Interrupts will be
|
||||||
|
* disabled.
|
||||||
|
* - Requires caution because there may be an interrupted execution of
|
||||||
|
* syslog_flush_intbuffer(): Only the outndx can be modified.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
int syslog_add_intbuffer(int ch)
|
int syslog_add_intbuffer(int ch)
|
||||||
{
|
{
|
||||||
#warning Missing logic
|
uint32_t inndx;
|
||||||
return -ENOSYS;
|
uint32_t outndx;
|
||||||
|
uint32_t endndx;
|
||||||
|
unsigned int inuse;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* How much space is left in the inbuffer? */
|
||||||
|
|
||||||
|
inndx = (uint32_t)g_syslog_intbuffer.si_inndx;
|
||||||
|
outndx = (uint32_t)g_syslog_intbuffer.si_outndx;
|
||||||
|
|
||||||
|
endndx = outndx;
|
||||||
|
if (endndx < outndx)
|
||||||
|
{
|
||||||
|
endndx += SYSLOG_INTBUFSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inuse = (unsigned int)(endndx - outndx);
|
||||||
|
|
||||||
|
/* Is there space for another character (reserving space for the overrun
|
||||||
|
* message)?
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (inuse == USABLE_INTBUFSIZE)
|
||||||
|
{
|
||||||
|
/* Copy the truncated message one character at a time, handing index
|
||||||
|
* wrap-around on each character.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = 0; i < SYSLOG_BUFOVERRUN_SIZE; i++)
|
||||||
|
{
|
||||||
|
/* Copy one character */
|
||||||
|
|
||||||
|
g_syslog_intbuffer.si_buffer[inndx] = (uint8_t)g_overrun_msg[i];
|
||||||
|
|
||||||
|
/* Increment the IN index, handling wrap-around */
|
||||||
|
|
||||||
|
if (++inndx >= SYSLOG_INTBUFSIZE)
|
||||||
|
{
|
||||||
|
inndx -= SYSLOG_INTBUFSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGASSERT(inndx != outndx);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_syslog_intbuffer.si_inndx = (uint16_t)inndx;
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
else if (inuse < USABLE_INTBUFSIZE)
|
||||||
|
{
|
||||||
|
/* Copy one character */
|
||||||
|
|
||||||
|
g_syslog_intbuffer.si_buffer[inndx] = (uint8_t)ch;
|
||||||
|
|
||||||
|
/* Increment the IN index, handling wrap-around */
|
||||||
|
|
||||||
|
if (++inndx >= SYSLOG_INTBUFSIZE)
|
||||||
|
{
|
||||||
|
inndx -= SYSLOG_INTBUFSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_syslog_intbuffer.si_inndx = (uint16_t)inndx;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This character goes to the bit bucket. We have already copied
|
||||||
|
* the overrun message so there is nothing else to do.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: syslog_flush_intbuffer
|
* Name: syslog_flush_intbuffer
|
||||||
@@ -108,8 +296,37 @@ int syslog_add_intbuffer(int ch)
|
|||||||
int syslog_flush_intbuffer(FAR const struct syslog_channel_s *channel,
|
int syslog_flush_intbuffer(FAR const struct syslog_channel_s *channel,
|
||||||
bool force)
|
bool force)
|
||||||
{
|
{
|
||||||
#warning Missing logic
|
syslog_putc_t putfunc;
|
||||||
return -ENOSYS;
|
int ch;
|
||||||
|
int ret = OK;
|
||||||
|
|
||||||
|
/* Select which putc function to use for this flush */
|
||||||
|
|
||||||
|
putfunc = force ? channel->sc_putc : channel->sc_force;
|
||||||
|
|
||||||
|
/* This logic is performed with the scheduler disabled to protect from
|
||||||
|
* concurrent modification by other tasks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sched_lock();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Transfer one character to time. This is inefficient, but is
|
||||||
|
* done in this way to: (1) Deal with concurrent modification of
|
||||||
|
* the interrutp buffer from interrupt activity, (2) Avoid keeper
|
||||||
|
* interrupts disabled for a long time, and (3) to handler
|
||||||
|
* wraparound of the circular buffer indices.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ch = syslog_remove_intbuffer();
|
||||||
|
if (ch != EOF)
|
||||||
|
{
|
||||||
|
ret = putfunc(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ch != EOF && ret >= 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_SYSLOG_INTBUFFER */
|
#endif /* CONFIG_SYSLOG_INTBUFFER */
|
||||||
|
|||||||
@@ -49,6 +49,9 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
/* Configuration ************************************************************/
|
/* Configuration ************************************************************/
|
||||||
/* CONFIG_SYSLOG - Enables generic system logging features.
|
/* CONFIG_SYSLOG - Enables generic system logging features.
|
||||||
|
* CONFIG_SYSLOG_INTBUFFER - Enables an interrupt buffer that will be used
|
||||||
|
* to serialize debug output from interrupt handlers.
|
||||||
|
* CONFIG_SYSLOG_INTBUFSIZE - The size of the interrupt buffer in bytes.
|
||||||
* CONFIG_SYSLOG_DEVPATH - The full path to the system logging device
|
* CONFIG_SYSLOG_DEVPATH - The full path to the system logging device
|
||||||
*
|
*
|
||||||
* In addition, some SYSLOG device must also be enabled that will provide
|
* In addition, some SYSLOG device must also be enabled that will provide
|
||||||
@@ -80,19 +83,31 @@
|
|||||||
# define CONFIG_SYSLOG_DEVPATH "/dev/ttyS1"
|
# define CONFIG_SYSLOG_DEVPATH "/dev/ttyS1"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_SYSLOG_INTBUFFER) && !defined(CONFIG_SYSLOG_INTBUFSIZE)
|
||||||
|
# define CONFIG_SYSLOG_INTBUFSIZE 2048
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_SYSLOG_INTBUFSIZE > 65535
|
||||||
|
# undef CONFIG_SYSLOG_INTBUFSIZE
|
||||||
|
# define CONFIG_SYSLOG_INTBUFSIZE 65535
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Types
|
* Public Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* This structure provides the interface to a SYSLOG device */
|
/* This structure provides the interface to a SYSLOG device */
|
||||||
|
|
||||||
|
typedef CODE int (*syslog_putc_t)(int ch);
|
||||||
|
typedef CODE int (*syslog_flush_t)(void);
|
||||||
|
|
||||||
struct syslog_channel_s
|
struct syslog_channel_s
|
||||||
{
|
{
|
||||||
/* I/O redirection methods */
|
/* I/O redirection methods */
|
||||||
|
|
||||||
CODE int (*sc_putc)(int ch); /* Normal buffered output */
|
syslog_putc_t sc_putc; /* Normal buffered output */
|
||||||
CODE int (*sc_force)(int ch); /* Low-level output for interrupt handlers */
|
syslog_putc_t sc_force; /* Low-level output for interrupt handlers */
|
||||||
CODE int (*sc_flush)(void); /* Flush buffered output (on crash) */
|
syslog_flush_t sc_flush; /* Flush buffered output (on crash) */
|
||||||
|
|
||||||
/* Implementation specific logic may follow */
|
/* Implementation specific logic may follow */
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user