SYSLOG: Add option to buffer SYSLOG output to avoid interleaving.
This commit is contained in:
parent
4f18b40429
commit
20727d17c3
@ -11,6 +11,12 @@ config ARCH_SYSLOG
|
||||
bool
|
||||
default n
|
||||
|
||||
# Selected if the SYSLOG device supports multi-byte write operations
|
||||
|
||||
config SYSLOG_WRITE
|
||||
bool
|
||||
default n
|
||||
|
||||
config RAMLOG
|
||||
bool "RAM log device support"
|
||||
default n
|
||||
@ -76,6 +82,30 @@ config DRIVER_NOTE
|
||||
to read data from the in-memory, scheduler instrumentation "note"
|
||||
buffer.
|
||||
|
||||
config SYSLOG_BUFFER
|
||||
bool "Use buffered output"
|
||||
default n
|
||||
depends on SYSLOG_WRITE
|
||||
---help---
|
||||
Enables an buffering logic that will be used to serialize debug
|
||||
output from concurrent tasks. This enables allocation of one buffer
|
||||
per thread, each of size CONFIG_SYSLOG_BUFSIZE.
|
||||
|
||||
The use of SYSLOG buffering is optional. If not enabled, however,
|
||||
then the output from multiple tasks that attempt to generate SYSLOG
|
||||
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
|
||||
bool "Use interrupt buffer"
|
||||
default n
|
||||
@ -108,6 +138,7 @@ choice
|
||||
|
||||
config SYSLOG_CHAR
|
||||
bool "Log to a character device"
|
||||
select SYSLOG_WRITE
|
||||
---help---
|
||||
Enable the generic character device for the SYSLOG. The full path to the
|
||||
SYSLOG device is provided by SYSLOG_DEVPATH. A valid character device (or
|
||||
@ -126,6 +157,7 @@ config SYSLOG_CONSOLE
|
||||
bool "Log to /dev/console"
|
||||
depends on DEV_CONSOLE
|
||||
select SYSLOG_SERIAL_CONSOLE if SERIAL_CONSOLE
|
||||
select SYSLOG_WRITE
|
||||
---help---
|
||||
Use the system console as a SYSLOG output device.
|
||||
|
||||
@ -140,6 +172,7 @@ endchoice
|
||||
config SYSLOG_FILE
|
||||
bool "Sylog file output"
|
||||
default n
|
||||
select SYSLOG_WRITE
|
||||
---help---
|
||||
Build in support to use a file to collect SYSOG output. File SYSLOG
|
||||
channels differ from other SYSLOG channels in that they cannot be
|
||||
|
@ -38,7 +38,7 @@
|
||||
# Include SYSLOG Infrastructure
|
||||
|
||||
CSRCS += vsyslog.c syslog_stream.c syslog_emergstream.c syslog_channel.c
|
||||
CSRCS += syslog_putc.c syslog_force.c syslog_flush.c
|
||||
CSRCS += syslog_putc.c syslog_write.c syslog_force.c syslog_flush.c
|
||||
|
||||
ifeq ($(CONFIG_SYSLOG_INTBUFFER),y)
|
||||
CSRCS += syslog_intbuffer.c
|
||||
|
@ -129,6 +129,9 @@ SYSLOG Channels
|
||||
{
|
||||
/* I/O redirection methods */
|
||||
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
syslog_write_t sc_write; /* Write multiple bytes */
|
||||
#endif
|
||||
syslog_putc_t sc_putc; /* Normal buffered output */
|
||||
syslog_putc_t sc_force; /* Low-level output for interrupt handlers */
|
||||
syslog_flush_t sc_flush; /* Flush buffered output (on crash) */
|
||||
|
@ -127,6 +127,9 @@ static int ramlog_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||
#ifdef CONFIG_RAMLOG_SYSLOG
|
||||
static const struct syslog_channel_s g_ramlog_syslog_channel =
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
syslog_default_write,
|
||||
#endif
|
||||
ramlog_putc,
|
||||
ramlog_putc,
|
||||
ramlog_flush
|
||||
|
@ -240,19 +240,57 @@ int syslog_flush_intbuffer(FAR const struct syslog_channel_s *channel,
|
||||
* Name: syslog_putc
|
||||
*
|
||||
* Description:
|
||||
* This is the low-level system logging interface.
|
||||
* This is the low-level, single character, system logging interface.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ch - The character to add to the SYSLOG (must be positive).
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the character is echoed back to the caller. A negated
|
||||
* errno value is returned on any failure.
|
||||
* On success, the character is echoed back to the caller. Minus one
|
||||
* is returned on any failure with the errno set correctly.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int syslog_putc(int ch);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_write
|
||||
*
|
||||
* Description:
|
||||
* This is the low-level, multiple character, system logging interface.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The buffer containing the data to be output
|
||||
* buflen - The number of bytes in the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the number of characters written is returned. A negated
|
||||
* errno value is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t syslog_write(FAR const char *buffer, size_t buflen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_default_write
|
||||
*
|
||||
* Description:
|
||||
* This provides a default write method for syslog devices that do not
|
||||
* support multiple byte writes This functions simply loops, outputting
|
||||
* one cahracter at a time.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The buffer containing the data to be output
|
||||
* buflen - The number of bytes in the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the number of characters written is returned. A negated
|
||||
* errno value is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t syslog_default_write(FAR const char *buffer, size_t buflen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_force
|
||||
*
|
||||
@ -272,6 +310,25 @@ int syslog_putc(int ch);
|
||||
|
||||
int syslog_force(int ch);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_dev_write
|
||||
*
|
||||
* Description:
|
||||
* This is the low-level, multile byte, system logging interface provided
|
||||
* for the character driver interface.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The buffer containing the data to be output
|
||||
* buflen - The number of bytes in the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the character is echoed back to the caller. Minus one
|
||||
* is returned on any failure with the errno set correctly.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t syslog_dev_write(FAR const char *buffer, size_t buflen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_dev_putc
|
||||
*
|
||||
|
@ -79,6 +79,9 @@ static int syslog_default_flush(void);
|
||||
#if defined(CONFIG_RAMLOG_SYSLOG)
|
||||
const struct syslog_channel_s g_default_channel =
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
syslog_default_write,
|
||||
#endif
|
||||
ramlog_putc,
|
||||
ramlog_putc,
|
||||
syslog_default_flush
|
||||
@ -86,6 +89,9 @@ const struct syslog_channel_s g_default_channel =
|
||||
#elif defined(HAVE_LOWPUTC)
|
||||
const struct syslog_channel_s g_default_channel =
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
syslog_default_write,
|
||||
#endif
|
||||
up_putc,
|
||||
up_putc,
|
||||
syslog_default_flush
|
||||
@ -93,6 +99,9 @@ const struct syslog_channel_s g_default_channel =
|
||||
#else
|
||||
const struct syslog_channel_s g_default_channel =
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
syslog_default_write,
|
||||
#endif
|
||||
syslog_default_putc,
|
||||
syslog_default_putc,
|
||||
syslog_default_flush
|
||||
|
@ -56,8 +56,8 @@
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t syslog_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen);
|
||||
static ssize_t syslog_chardev_write(FAR struct file *filep,
|
||||
FAR const char *buffer, size_t buflen);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
@ -68,7 +68,7 @@ static const struct file_operations syslog_fops =
|
||||
NULL, /* open */
|
||||
NULL, /* close */
|
||||
NULL, /* read */
|
||||
syslog_write, /* write */
|
||||
syslog_chardev_write, /* write */
|
||||
NULL, /* seek */
|
||||
NULL /* ioctl */
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
@ -84,23 +84,13 @@ static const struct file_operations syslog_fops =
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_write
|
||||
* Name: syslog_chardev_write
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t syslog_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t len)
|
||||
static ssize_t syslog_chardev_write(FAR struct file *filep,
|
||||
FAR const char *buffer, size_t len)
|
||||
{
|
||||
size_t nwritten;
|
||||
int ret;
|
||||
|
||||
for (nwritten = 0; nwritten < len; nwritten++)
|
||||
{
|
||||
int ch = *buffer++;
|
||||
ret = syslog_putc(ch);
|
||||
UNUSED(ret);
|
||||
}
|
||||
|
||||
return len;
|
||||
return syslog_write(buffer, len);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -106,14 +106,7 @@ static ssize_t syslog_console_read(FAR struct file *filep, FAR char *buffer,
|
||||
static ssize_t syslog_console_write(FAR struct file *filep,
|
||||
FAR const char *buffer, size_t buflen)
|
||||
{
|
||||
ssize_t ret = buflen;
|
||||
|
||||
for (; buflen; buflen--)
|
||||
{
|
||||
syslog_putc(*buffer++);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return syslog_write(buffer, len);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -83,6 +83,9 @@ static int syslog_console_force(int ch);
|
||||
|
||||
static const struct syslog_channel_s g_syslog_console_channel =
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
syslog_dev_write,
|
||||
#endif
|
||||
syslog_dev_putc,
|
||||
#ifdef HAVE_LOWPUTC
|
||||
up_putc,
|
||||
|
@ -74,6 +74,9 @@ static int syslog_devchan_force(int ch);
|
||||
|
||||
static const struct syslog_channel_s g_syslog_dev_channel =
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
syslog_dev_write,
|
||||
#endif
|
||||
#ifdef CONFIG_SYSLOG_CHAR_CRLF
|
||||
syslog_devchan_putc,
|
||||
#else
|
||||
|
@ -184,6 +184,114 @@ static inline void syslog_dev_givesem(void)
|
||||
sem_post(&g_syslog_dev.sl_sem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_dev_outputready
|
||||
*
|
||||
* Description:
|
||||
* Ignore any output:
|
||||
*
|
||||
* (1) Before the SYSLOG device has been initialized. This could happen
|
||||
* from debug output that occurs early in the boot sequence before
|
||||
* syslog_dev_initialize() is called (SYSLOG_UNINITIALIZED).
|
||||
* (2) While the device is being initialized. The case could happen if
|
||||
* debug output is generated while syslog_dev_initialize() executes
|
||||
* (SYSLOG_INITIALIZING).
|
||||
* (3) While we are generating SYSLOG output. The case could happen if
|
||||
* debug output is generated while syslog_dev_putc() executes
|
||||
* (This case is actually handled inside of syslog_semtake()).
|
||||
* (4) Any debug output generated from interrupt handlers. A disadvantage
|
||||
* of using the generic character device for the SYSLOG is that it
|
||||
* cannot handle debug output generated from interrupt level handlers.
|
||||
* (5) Any debug output generated from the IDLE loop. The character
|
||||
* driver interface is blocking and the IDLE thread is not permitted
|
||||
* to block.
|
||||
* (6) If an irrecoverable failure occurred during initialization. In
|
||||
* this case, we won't ever bother to try again (ever).
|
||||
*
|
||||
* NOTE: That the third case is different. It applies only to the thread
|
||||
* that currently holds the sl_sem sempaphore. Other threads should wait.
|
||||
* that is why that case is handled in syslog_semtake().
|
||||
*
|
||||
* Input Parameters:
|
||||
* ch - The character to add to the SYSLOG (must be positive).
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the character is echoed back to the caller. A negated
|
||||
* errno value is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int syslog_dev_outputready(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Cases (4) and (5) */
|
||||
|
||||
if (up_interrupt_context() || getpid() == 0)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* We can save checks in the usual case: That after the SYSLOG device
|
||||
* has been successfully opened.
|
||||
*/
|
||||
|
||||
if (g_syslog_dev.sl_state != SYSLOG_OPENED)
|
||||
{
|
||||
/* Case (1) and (2) */
|
||||
|
||||
if (g_syslog_dev.sl_state == SYSLOG_UNINITIALIZED ||
|
||||
g_syslog_dev.sl_state == SYSLOG_INITIALIZING)
|
||||
{
|
||||
return -EAGAIN; /* Can't access the SYSLOG now... maybe next time? */
|
||||
}
|
||||
|
||||
/* Case (6) */
|
||||
|
||||
if (g_syslog_dev.sl_state == SYSLOG_FAILURE)
|
||||
{
|
||||
return -ENXIO; /* There is no SYSLOG device */
|
||||
}
|
||||
|
||||
/* syslog_dev_initialize() is called as soon as enough of the operating
|
||||
* system is in place to support the open operation... but it is
|
||||
* possible that the SYSLOG device is not yet registered at that time.
|
||||
* In this case, we know that the system is sufficiently initialized
|
||||
* to support an attempt to re-open the SYSLOG device.
|
||||
*
|
||||
* NOTE that the scheduler is locked. That is because we do not have
|
||||
* fully initialized semaphore capability until the SYSLOG device is
|
||||
* successfully initialized
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
if (g_syslog_dev.sl_state == SYSLOG_REOPEN)
|
||||
{
|
||||
/* Try again to initialize the device. We may do this repeatedly
|
||||
* because the log device might be something that was not ready
|
||||
* the first time that syslog_dev_initializee() was called (such as a
|
||||
* USB serial device that has not yet been connected or a file in
|
||||
* an NFS mounted file system that has not yet been mounted).
|
||||
*/
|
||||
|
||||
DEBUGASSERT(g_syslog_dev.sl_devpath != NULL);
|
||||
ret = syslog_dev_initialize(g_syslog_dev.sl_devpath,
|
||||
(int)g_syslog_dev.sl_oflags,
|
||||
(int)g_syslog_dev.sl_mode);
|
||||
if (ret < 0)
|
||||
{
|
||||
sched_unlock();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
DEBUGASSERT(g_syslog_dev.sl_state == SYSLOG_OPENED);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -354,19 +462,167 @@ int syslog_dev_uninitialize(void)
|
||||
}
|
||||
#endif /* CONFIG_SYSLOG_FILE */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_dev_write
|
||||
*
|
||||
* Description:
|
||||
* This is the low-level, multile byte, system logging interface provided
|
||||
* for the character driver interface.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The buffer containing the data to be output
|
||||
* buflen - The number of bytes in the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the character is echoed back to the caller. Minus one
|
||||
* is returned on any failure with the errno set correctly.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t syslog_dev_write(FAR const char *buffer, size_t buflen)
|
||||
{
|
||||
FAR const char *endptr;
|
||||
ssize_t nwritten;
|
||||
size_t writelen;
|
||||
int errcode;
|
||||
int ret;
|
||||
|
||||
/* Check if the system is ready to do output operations */
|
||||
|
||||
ret = syslog_dev_outputready();
|
||||
if (ret < 0)
|
||||
{
|
||||
errcode = -ret;
|
||||
goto errout_with_errcode;
|
||||
}
|
||||
|
||||
/* The syslog device is ready for writing */
|
||||
|
||||
ret = syslog_dev_takesem();
|
||||
if (ret < 0)
|
||||
{
|
||||
/* We probably already hold the semaphore and were probably
|
||||
* re-entered by the logic kicked off by file_write().
|
||||
* We might also have been interrupted by a signal. Either
|
||||
* way, we are outta here.
|
||||
*/
|
||||
|
||||
errcode = -ret;
|
||||
goto errout_with_errcode;
|
||||
}
|
||||
|
||||
/* Loop until we have output all characters */
|
||||
|
||||
for (endptr = buffer; *endptr != '\n'; endptr++)
|
||||
{
|
||||
switch (*endptr)
|
||||
{
|
||||
case '\r':
|
||||
{
|
||||
/* Write everything up to this point, ignore the carriage
|
||||
* return.
|
||||
*
|
||||
* - buffer points to next byte to output.
|
||||
* - endptr points to the carriage return.
|
||||
*/
|
||||
|
||||
writelen = (size_t)((uintptr_t)endptr - (uintptr_t)buffer);
|
||||
if (writelen > 0)
|
||||
{
|
||||
nwritten = file_write(&g_syslog_dev.sl_file, buffer, writelen);
|
||||
if (nwritten < 0)
|
||||
{
|
||||
errcode = -nwritten;
|
||||
goto errout_with_sem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust pointers */
|
||||
|
||||
writelen++; /* Skip the carriage return */
|
||||
buffer += writelen; /* Points past the carriage return */
|
||||
}
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
{
|
||||
/* Write everything up to this point, then add a carriage
|
||||
* return and linefeed;
|
||||
*
|
||||
* - buffer points to next byte to output.
|
||||
* - endptr points to the new line.
|
||||
*/
|
||||
|
||||
writelen = (size_t)((uintptr_t)endptr - (uintptr_t)buffer);
|
||||
if (writelen > 0)
|
||||
{
|
||||
nwritten = file_write(&g_syslog_dev.sl_file, buffer, writelen);
|
||||
if (nwritten < 0)
|
||||
{
|
||||
errcode = -nwritten;
|
||||
goto errout_with_sem;
|
||||
}
|
||||
}
|
||||
|
||||
nwritten = file_write(&g_syslog_dev.sl_file, g_syscrlf, 2);
|
||||
if (nwritten < 0)
|
||||
{
|
||||
errcode = -nwritten;
|
||||
goto errout_with_sem;
|
||||
}
|
||||
|
||||
/* Adjust pointers */
|
||||
|
||||
writelen++; /* Skip the line feed */
|
||||
buffer += writelen; /* Points past the line feed */
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write any data at the end of the buffer.
|
||||
*
|
||||
* - buffer points to next byte to output.
|
||||
* - endptr points to the NULL terminator.
|
||||
*/
|
||||
|
||||
writelen = (size_t)((uintptr_t)endptr - (uintptr_t)buffer);
|
||||
if (writelen > 0)
|
||||
{
|
||||
nwritten = file_write(&g_syslog_dev.sl_file, buffer, writelen);
|
||||
if (nwritten < 0)
|
||||
{
|
||||
errcode = -nwritten;
|
||||
goto errout_with_sem;
|
||||
}
|
||||
}
|
||||
|
||||
syslog_dev_givesem();
|
||||
return buflen;
|
||||
|
||||
errout_with_sem:
|
||||
syslog_dev_givesem();
|
||||
errout_with_errcode:
|
||||
set_errno(errcode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_dev_putc
|
||||
*
|
||||
* Description:
|
||||
* This is the low-level system logging interface provided for the
|
||||
* character driver interface.
|
||||
* This is the low-level, single character, system logging interface
|
||||
* provided for the character driver interface.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ch - The character to add to the SYSLOG (must be positive).
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the character is echoed back to the caller. A negated
|
||||
* errno value is returned on any failure.
|
||||
* On success, the character is echoed back to the caller. Minus one
|
||||
* is returned on any failure with the errno set correctly.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@ -377,99 +633,15 @@ int syslog_dev_putc(int ch)
|
||||
int errcode;
|
||||
int ret;
|
||||
|
||||
/* Ignore any output:
|
||||
*
|
||||
* (1) Before the SYSLOG device has been initialized. This could happen
|
||||
* from debug output that occurs early in the boot sequence before
|
||||
* syslog_dev_initialize() is called (SYSLOG_UNINITIALIZED).
|
||||
* (2) While the device is being initialized. The case could happen if
|
||||
* debug output is generated while syslog_dev_initialize() executes
|
||||
* (SYSLOG_INITIALIZING).
|
||||
* (3) While we are generating SYSLOG output. The case could happen if
|
||||
* debug output is generated while syslog_dev_putc() executes
|
||||
* (This case is actually handled inside of syslog_semtake()).
|
||||
* (4) Any debug output generated from interrupt handlers. A disadvantage
|
||||
* of using the generic character device for the SYSLOG is that it
|
||||
* cannot handle debug output generated from interrupt level handlers.
|
||||
* (5) Any debug output generated from the IDLE loop. The character
|
||||
* driver interface is blocking and the IDLE thread is not permitted
|
||||
* to block.
|
||||
* (6) If an irrecoverable failure occurred during initialization. In
|
||||
* this case, we won't ever bother to try again (ever).
|
||||
*
|
||||
* NOTE: That the third case is different. It applies only to the thread
|
||||
* that currently holds the sl_sem sempaphore. Other threads should wait.
|
||||
* that is why that case is handled in syslog_semtake().
|
||||
*/
|
||||
/* Check if the system is ready to do output operations */
|
||||
|
||||
/* Cases (4) and (5) */
|
||||
|
||||
if (up_interrupt_context() || getpid() == 0)
|
||||
ret = syslog_dev_outputready();
|
||||
if (ret < 0)
|
||||
{
|
||||
errcode = ENOSYS;
|
||||
errcode = -ret;
|
||||
goto errout_with_errcode;
|
||||
}
|
||||
|
||||
/* We can save checks in the usual case: That after the SYSLOG device
|
||||
* has been successfully opened.
|
||||
*/
|
||||
|
||||
if (g_syslog_dev.sl_state != SYSLOG_OPENED)
|
||||
{
|
||||
/* Case (1) and (2) */
|
||||
|
||||
if (g_syslog_dev.sl_state == SYSLOG_UNINITIALIZED ||
|
||||
g_syslog_dev.sl_state == SYSLOG_INITIALIZING)
|
||||
{
|
||||
errcode = EAGAIN; /* Can't access the SYSLOG now... maybe next time? */
|
||||
goto errout_with_errcode;
|
||||
}
|
||||
|
||||
/* Case (6) */
|
||||
|
||||
if (g_syslog_dev.sl_state == SYSLOG_FAILURE)
|
||||
{
|
||||
errcode = ENXIO; /* There is no SYSLOG device */
|
||||
goto errout_with_errcode;
|
||||
}
|
||||
|
||||
/* syslog_dev_initialize() is called as soon as enough of the operating
|
||||
* system is in place to support the open operation... but it is
|
||||
* possible that the SYSLOG device is not yet registered at that time.
|
||||
* In this case, we know that the system is sufficiently initialized
|
||||
* to support an attempt to re-open the SYSLOG device.
|
||||
*
|
||||
* NOTE that the scheduler is locked. That is because we do not have
|
||||
* fully initialized semaphore capability until the SYSLOG device is
|
||||
* successfully initialized
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
if (g_syslog_dev.sl_state == SYSLOG_REOPEN)
|
||||
{
|
||||
/* Try again to initialize the device. We may do this repeatedly
|
||||
* because the log device might be something that was not ready
|
||||
* the first time that syslog_dev_initializee() was called (such as a
|
||||
* USB serial device that has not yet been connected or a file in
|
||||
* an NFS mounted file system that has not yet been mounted).
|
||||
*/
|
||||
|
||||
DEBUGASSERT(g_syslog_dev.sl_devpath != NULL);
|
||||
ret = syslog_dev_initialize(g_syslog_dev.sl_devpath,
|
||||
(int)g_syslog_dev.sl_oflags,
|
||||
(int)g_syslog_dev.sl_mode);
|
||||
if (ret < 0)
|
||||
{
|
||||
sched_unlock();
|
||||
errcode = -ret;
|
||||
goto errout_with_errcode;
|
||||
}
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
DEBUGASSERT(g_syslog_dev.sl_state == SYSLOG_OPENED);
|
||||
}
|
||||
|
||||
/* Ignore carriage returns */
|
||||
|
||||
if (ch == '\r')
|
||||
|
@ -99,7 +99,7 @@ static void emergstream_putc(FAR struct lib_outstream_s *this, int ch)
|
||||
*
|
||||
* Input parameters:
|
||||
* stream - User allocated, uninitialized instance of struct
|
||||
* lib_lowoutstream_s to be initialized.
|
||||
* lib_outstream_s to be initialized.
|
||||
*
|
||||
* Returned Value:
|
||||
* None (User allocated instance initialized).
|
||||
|
@ -72,6 +72,9 @@ static int syslog_file_force(int ch);
|
||||
|
||||
static const struct syslog_channel_s g_syslog_file_channel =
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
syslog_dev_write,
|
||||
#endif
|
||||
syslog_dev_putc,
|
||||
syslog_file_force,
|
||||
syslog_dev_flush,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* drivers/syslog/syslog_stream.c
|
||||
*
|
||||
* Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2012, 2016-2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -59,6 +59,24 @@
|
||||
|
||||
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;
|
||||
|
||||
/* Add the incoming character to the buffer */
|
||||
|
||||
stream->buf[stream->nbuf] = ch;
|
||||
stream->nbuf++;
|
||||
this->nput++;
|
||||
|
||||
/* Is the buffer full? Did we encounter a new line? */
|
||||
|
||||
if (stream->nbuf >= CONFIG_SYSLOG_BUFSIZE || ch == '\n')
|
||||
{
|
||||
/* Yes.. then flush the buffer */
|
||||
|
||||
(void)this->flush(this);
|
||||
}
|
||||
#else
|
||||
int ret;
|
||||
|
||||
/* Try writing until the write was successful or until an irrecoverable
|
||||
@ -83,9 +101,46 @@ static void syslogstream_putc(FAR struct lib_outstream_s *this, int ch)
|
||||
* ignored in this context.
|
||||
*/
|
||||
}
|
||||
while (errno == -EINTR);
|
||||
while (get_errno() == -EINTR);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslogstream_flush
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SYSLOG_BUFFER
|
||||
static int syslogstream_flush(FAR struct lib_outstream_s *this)
|
||||
{
|
||||
FAR struct lib_syslogstream_s *stream = (FAR struct lib_syslogstream_s *)this;
|
||||
int ret = OK;
|
||||
|
||||
/* Is there anything buffered? */
|
||||
|
||||
if (stream->nbuf > 0)
|
||||
{
|
||||
/* Yes write the buffered data */
|
||||
|
||||
do
|
||||
{
|
||||
int status = syslog_write(stream->buf, stream->nbuf);
|
||||
if (status < 0)
|
||||
{
|
||||
ret = -get_errno();
|
||||
}
|
||||
else
|
||||
{
|
||||
stream->nbuf = 0;
|
||||
ret = OK;
|
||||
}
|
||||
}
|
||||
while (ret == -EINTR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -99,16 +154,23 @@ static void syslogstream_putc(FAR struct lib_outstream_s *this, int ch)
|
||||
*
|
||||
* Input parameters:
|
||||
* stream - User allocated, uninitialized instance of struct
|
||||
* lib_lowoutstream_s to be initialized.
|
||||
* lib_syslogstream_s to be initialized.
|
||||
*
|
||||
* Returned Value:
|
||||
* None (User allocated instance initialized).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void syslogstream(FAR struct lib_outstream_s *stream)
|
||||
void syslogstream(FAR struct lib_syslogstream_s *stream)
|
||||
{
|
||||
stream->put = syslogstream_putc;
|
||||
stream->flush = lib_noflush;
|
||||
stream->nput = 0;
|
||||
#ifdef CONFIG_SYSLOG_BUFFER
|
||||
stream->public.put = syslogstream_putc;
|
||||
stream->public.flush = syslogstream_flush;
|
||||
stream->public.nput = 0;
|
||||
stream->nbuf = 0;
|
||||
#else
|
||||
stream->public.put = syslogstream_putc;
|
||||
stream->public.flush = lib_noflush;
|
||||
stream->public.nput = 0;
|
||||
#endif
|
||||
}
|
||||
|
107
drivers/syslog/syslog_write.c
Normal file
107
drivers/syslog/syslog_write.c
Normal file
@ -0,0 +1,107 @@
|
||||
/****************************************************************************
|
||||
* drivers/syslog/syslog_write.c
|
||||
*
|
||||
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <nuttx/syslog/syslog.h>
|
||||
|
||||
#include "syslog.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_default_write
|
||||
*
|
||||
* Description:
|
||||
* This provides a default write method for syslog devices that do not
|
||||
* support multiple byte writes This functions simply loops, outputting
|
||||
* one cahracter at a time.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The buffer containing the data to be output
|
||||
* buflen - The number of bytes in the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the number of characters written is returned. A negated
|
||||
* errno value is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t syslog_default_write(FAR const char *buffer, size_t buflen)
|
||||
{
|
||||
size_t nwritten;
|
||||
int ret;
|
||||
|
||||
for (nwritten = 0; nwritten < buflen; nwritten++)
|
||||
{
|
||||
int ch = *buffer++;
|
||||
ret = syslog_putc(ch);
|
||||
UNUSED(ret);
|
||||
}
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: syslog_write
|
||||
*
|
||||
* Description:
|
||||
* This is the low-level, multiple character, system logging interface.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buffer - The buffer containing the data to be output
|
||||
* buflen - The number of bytes in the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the number of characters written is returned. A negated
|
||||
* errno value is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t syslog_write(FAR const char *buffer, size_t buflen)
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
return g_syslog_channel->sc_write(buffer, buflen);
|
||||
#else
|
||||
return syslog_default_write(buffer, buflen);
|
||||
#endif
|
||||
}
|
@ -67,7 +67,7 @@
|
||||
|
||||
int _vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap)
|
||||
{
|
||||
struct lib_outstream_s stream;
|
||||
struct lib_syslogstream_s stream;
|
||||
#ifdef CONFIG_SYSLOG_TIMESTAMP
|
||||
struct timespec ts;
|
||||
int ret = -1;
|
||||
@ -114,7 +114,7 @@ int _vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap)
|
||||
{
|
||||
/* Use the normal SYSLOG stream */
|
||||
|
||||
syslogstream((FAR struct lib_outstream_s *)&stream);
|
||||
syslogstream((FAR struct lib_syslogstream_s *)&stream);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SYSLOG_TIMESTAMP)
|
||||
|
@ -189,6 +189,18 @@ struct lib_rawsostream_s
|
||||
int fd;
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
|
||||
struct lib_syslogstream_s
|
||||
{
|
||||
struct lib_outstream_s public;
|
||||
#ifdef CONFIG_SYSLOG_BUFFER
|
||||
unsigned int nbuf;
|
||||
char buf[CONFIG_SYSLOG_BUFSIZE];
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
@ -360,7 +372,7 @@ void lib_nulloutstream(FAR struct lib_outstream_s *nulloutstream);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void syslogstream(FAR struct lib_outstream_s *stream);
|
||||
void syslogstream(FAR struct lib_syslogstream_s *stream);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: emergstream
|
||||
|
@ -43,6 +43,8 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/compiler.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/****************************************************************************
|
||||
@ -104,6 +106,7 @@ enum syslog_init_e
|
||||
|
||||
/* This structure provides the interface to a SYSLOG device */
|
||||
|
||||
typedef CODE ssize_t (*syslog_write_t)(FAR const char *buf, size_t buflen);
|
||||
typedef CODE int (*syslog_putc_t)(int ch);
|
||||
typedef CODE int (*syslog_flush_t)(void);
|
||||
|
||||
@ -111,8 +114,11 @@ struct syslog_channel_s
|
||||
{
|
||||
/* I/O redirection methods */
|
||||
|
||||
syslog_putc_t sc_putc; /* Normal buffered output */
|
||||
syslog_putc_t sc_force; /* Low-level output for interrupt handlers */
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
syslog_write_t sc_write; /* Write multiple bytes */
|
||||
#endif
|
||||
syslog_putc_t sc_putc; /* Normal buffered output */
|
||||
syslog_putc_t sc_force; /* Low-level output for interrupt handlers */
|
||||
syslog_flush_t sc_flush; /* Flush buffered output (on crash) */
|
||||
|
||||
/* Implementation specific logic may follow */
|
||||
|
Loading…
Reference in New Issue
Block a user