diff options
Diffstat (limited to 'runtime/print.c')
-rw-r--r-- | runtime/print.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/runtime/print.c b/runtime/print.c new file mode 100644 index 00000000..8b0d267d --- /dev/null +++ b/runtime/print.c @@ -0,0 +1,168 @@ +#ifndef _PRINT_C_ /* -*- linux-c -*- */ +#define _PRINT_C_ + +#include <linux/config.h> + +#include "io.c" + +/** @file print.c + * @addtogroup print Print Buffer + * Print Buffer Functions. + * The print buffer is for collecting output to send to the user daemon. + * This is a per-cpu static buffer. The buffer is sent when + * _stp_print_flush() is called. + * @{ + */ + +/** Size of buffer, not including terminating NULL */ +#define STP_PRINT_BUF_LEN 8000 + +static int _stp_pbuf_len[NR_CPUS]; + +#ifdef STP_NETLINK_ONLY +#define STP_PRINT_BUF_START 0 +static char _stp_pbuf[NR_CPUS][STP_PRINT_BUF_LEN + 1]; + +void _stp_print_flush (void) +{ + int cpu = smp_processor_id(); + char *buf = &_stp_pbuf[cpu][0]; + int len = _stp_pbuf_len[cpu]; + + if (len == 0) + return; + + if ( app.logging == 0) { + _stp_pbuf_len[cpu] = 0; + return; + } + + /* enforce newline at end */ + if (buf[len - 1] != '\n') { + buf[len++] = '\n'; + buf[len] = '\0'; + } + + send_reply (STP_REALTIME_DATA, buf, len + 1, stpd_pid); + _stp_pbuf_len[cpu] = 0; +} + +#else /* ! STP_NETLINK_ONLY */ +/* size of timestamp, in bytes, including space */ +#define TIMESTAMP_SIZE 19 +#define STP_PRINT_BUF_START (TIMESTAMP_SIZE + 1) +static char _stp_pbuf[NR_CPUS][STP_PRINT_BUF_LEN + STP_PRINT_BUF_START + 1]; + +void _stp_print_flush (void) +{ + int cpu = smp_processor_id(); + char *buf = &_stp_pbuf[cpu][0]; + char *ptr = buf + STP_PRINT_BUF_START; + struct timeval tv; + + if (_stp_pbuf_len[cpu] == 0) + return; + + /* enforce newline at end */ + if (ptr[_stp_pbuf_len[cpu]-1] != '\n') { + ptr[_stp_pbuf_len[cpu]++] = '\n'; + ptr[_stp_pbuf_len[cpu]] = '\0'; + } + + do_gettimeofday(&tv); + scnprintf (buf, TIMESTAMP_SIZE+1, "[%li.%06li] ", tv.tv_sec, tv.tv_usec); + buf[TIMESTAMP_SIZE] = ' '; + relayapp_write(buf, _stp_pbuf_len[cpu] + TIMESTAMP_SIZE + 2); + _stp_pbuf_len[cpu] = 0; +} +#endif /* STP_NETLINK_ONLY */ + +/** Sprint into the scratch buffer. + * Like printf, except output goes into a global scratch buffer + * which will contain the null-terminated output. + * Safe because overflowing the buffer is not allowed. + * Size is limited by length of scratch buffer, STP_BUF_LEN. + * + * @param fmt A printf-style format string followed by a + * variable number of args. + * @sa _stp_pbuf_clear + */ + +void _stp_printf (const char *fmt, ...) +{ + int num; + va_list args; + int cpu = smp_processor_id(); + char *buf = &_stp_pbuf[cpu][STP_PRINT_BUF_START] + _stp_pbuf_len[cpu]; + va_start(args, fmt); + num = vscnprintf(buf, STP_PRINT_BUF_LEN - _stp_pbuf_len[cpu], fmt, args); + va_end(args); + if (num > 0) + _stp_pbuf_len[cpu] += num; +} + +void _stp_vprintf (const char *fmt, va_list args) +{ + int num; + int cpu = smp_processor_id(); + char *buf = &_stp_pbuf[cpu][STP_PRINT_BUF_START] + _stp_pbuf_len[cpu]; + num = vscnprintf(buf, STP_PRINT_BUF_LEN -_stp_pbuf_len[cpu], fmt, args); + if (num > 0) + _stp_pbuf_len[cpu] += num; +} + +/** Write a string into the scratch buffer. + * Copies a string into a global scratch buffer. + * Safe because overflowing the buffer is not allowed. + * Size is limited by length of scratch buffer, STP_BUF_LEN. + * This is more efficient than using _stp_sprint(). + * + * @param str A string. + */ + +void _stp_print_cstr (const char *str) +{ + int cpu = smp_processor_id(); + char *buf = &_stp_pbuf[cpu][STP_PRINT_BUF_START] + _stp_pbuf_len[cpu]; + int num = strlen (str); + if (num > STP_PRINT_BUF_LEN - _stp_pbuf_len[cpu]) + num = STP_PRINT_BUF_LEN - _stp_pbuf_len[cpu]; + strncpy (buf, str, num+1); + _stp_pbuf_len[cpu] += num; +} + +/** Clear the scratch buffer. + * This function should be called before anything is written to + * the scratch buffer. Output will accumulate in the buffer + * until this function is called again. + * @returns A pointer to the buffer. + */ + +char *_stp_print_clear (void) +{ + int cpu = smp_processor_id(); + _stp_pbuf_len[cpu] = 0; + return &_stp_pbuf[cpu][STP_PRINT_BUF_START]; +} + +#include "string.c" + +void _stp_print_string (String str) +{ + if (str->len) + _stp_print_cstr (str->buf); +} + +#define _stp_print(str) \ + ({ \ + if (__builtin_types_compatible_p (typeof (str), char[])) { \ + char *x = (char *)str; \ + _stp_print_cstr(x); \ + } else { \ + String x = (String)str; \ + _stp_print_string(x); \ + } \ + }) + +/** @} */ +#endif /* _PRINT_C_ */ |