summaryrefslogtreecommitdiffstats
path: root/runtime/user/print.c
diff options
context:
space:
mode:
authorhunt <hunt>2005-05-18 00:16:33 +0000
committerhunt <hunt>2005-05-18 00:16:33 +0000
commit4ed11cee2365c604b3c2a39a846706cc0ae0ac1a (patch)
tree0743e2c0c4d85bc66b74835869464d1038fe03f1 /runtime/user/print.c
parent43614f5d7e0d18f553c0ee2a4e195d7b8f63be1f (diff)
downloadsystemtap-steved-4ed11cee2365c604b3c2a39a846706cc0ae0ac1a.tar.gz
systemtap-steved-4ed11cee2365c604b3c2a39a846706cc0ae0ac1a.tar.xz
systemtap-steved-4ed11cee2365c604b3c2a39a846706cc0ae0ac1a.zip
User space test stuff.
Diffstat (limited to 'runtime/user/print.c')
-rw-r--r--runtime/user/print.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/runtime/user/print.c b/runtime/user/print.c
new file mode 100644
index 00000000..c8fcf3e1
--- /dev/null
+++ b/runtime/user/print.c
@@ -0,0 +1,161 @@
+#ifndef _PRINT_C_ /* -*- linux-c -*- */
+#define _PRINT_C_
+
+#include <linux/config.h>
+#include <stdio.h>
+
+/** @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.
+ *
+ * The reason to do this is to allow multiple small prints to be combined then
+ * timestamped and sent together to stpd. It could flush automatically on newlines,
+ * but what about stack traces which span many lines? So try this and see how it works for us.
+ * @{
+ */
+
+/** Size of buffer, not including terminating NULL */
+#define STP_PRINT_BUF_LEN 8000
+
+static int _stp_pbuf_len[NR_CPUS];
+
+#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;
+
+ /* enforce newline at end */
+ if (buf[len - 1] != '\n') {
+ buf[len++] = '\n';
+ buf[len] = '\0';
+ }
+
+ fwrite (buf, len, 1, stdout);
+ _stp_pbuf_len[cpu] = 0;
+}
+
+
+/** Print into the print buffer.
+ * Like printf, except output goes to the print buffer.
+ * Safe because overflowing the buffer is not allowed.
+ * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
+ *
+ * @param fmt A printf-style format string followed by a
+ * variable number of args.
+ * @sa _stp_print_flush()
+ */
+
+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);
+// dbug ("%d bytes to %lx %lx\n", STP_PRINT_BUF_LEN - _stp_pbuf_len[cpu], buf, &_stp_pbuf[cpu][STP_PRINT_BUF_START]);
+ num = vsnprintf(buf, STP_PRINT_BUF_LEN - _stp_pbuf_len[cpu], fmt, args);
+// dbug ("num = %d\n", num);
+ va_end(args);
+ if (num > 0 && num <= STP_PRINT_BUF_LEN - _stp_pbuf_len[cpu])
+ _stp_pbuf_len[cpu] += num;
+}
+
+/** Print into the print buffer.
+ * Use this if your function already has a va_list.
+ * You probably want _stp_printf().
+ */
+
+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 = vsnprintf(buf, STP_PRINT_BUF_LEN -_stp_pbuf_len[cpu], fmt, args);
+ if (num > 0)
+ _stp_pbuf_len[cpu] += num;
+}
+
+/** Write a C string into the print buffer.
+ * Copies a string into a print buffer.
+ * Safe because overflowing the buffer is not allowed.
+ * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
+ * This is more efficient than using _stp_printf() if you don't
+ * need fancy formatting.
+ *
+ * @param str A C string.
+ * @sa _stp_print
+ */
+
+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"
+
+/** Write a String into the print buffer.
+ * Copies a String into a print buffer.
+ * Safe because overflowing the buffer is not allowed.
+ * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
+ * This is more efficient than using _stp_printf() if you don't
+ * need fancy formatting.
+ *
+ * @param str A String.
+ * @sa _stp_print
+ */
+
+void _stp_print_string (String str)
+{
+ if (str->len)
+ _stp_print_cstr (str->buf);
+}
+
+/** Write a String or C string into the print buffer.
+ * This macro selects the proper function to call.
+ * @param str A String or C string (char *)
+ * @sa _stp_print_cstr _stp_print_string
+ */
+
+#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_ */